Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Help in Understanding Interfaces

Status
Not open for further replies.

bitseeker

Programmer
Nov 27, 2005
60
US
I'm learning about interfaces, and I found thread678-812597 to be useful, along with snippets from many other
posts. I've been having a hard time connecting the general statements about what interfaces are used for
with concrete examples (and there are plenty of both...). I think I may have figured something about this out
and was hoping to post that understanding here and get some feedback to fine tune it (or trash it and start
over!)

Here's the view I came up with.
----------------------
Interfaces are very useful in the DESIGN of an app, and the payoff comes in the CODING and the later the MAINTENANCE of the app.

Even if I'm coding an app myself, as a one-person team, there's a lot to remember. If I use interfaces to
describe general relationships between different areas of code, that allows me to work inside those areas of
code one at a time without having to remember (or more likely, constantly go check) what is going on in
some other area.

The thing that has thrown me off in the concrete examples of interfaces is that I could never see the "design
intent" behind them (though this gives me an inkling into the use of what "intention" means in "Foundations of
OOP Using .Net 2.0 Patterns" by Christian Gross").

So what I came to is that you have to, somewhere, define what the methods and attributes inside the
interface are. That is, if you specify a "save" method in an interface, you have to somewhere (such as in
in-line documentation), say, "the 'save' method is used to write objects to the database". So in a sense,
you're writing high level pseudo code (like in a "mock object" from thread678-971775 ) that expresses what
the interface is supposed to enforce (note, "enforce", not "do"). THAT's the "media" that connects the high
level design intent to the actual specification of an interface in code. THAT's what makes an interface mean
something, and how interfaces do their job of "locking" designs into the code. (I think in all the examples I've
seen these descriptions were assumed by context.)

So you could do a lot of design work using interfaces (or conceptual interfaces, before they are coded) describing the relationships between large areas of code (groups of classes, etc.) before starting to work on the details.

So in one sense, the "contract" is between the client and the serving classes, but in another sense the
"contract" is between the designer and the coder (aha, another inkling about what Gross is talking about in
book cited above).

So in a sense, the reason interfaces don't "do" very much in code is that they are mostly DESIGN tools, that
enforce behavior on the coding process. They're not supposed to make bits move, they're supposed to keep
programmers on track.

Then I can see there's another whole layer, which is basically programmer management, that's required to
get the programmer (which would include myself, in my one person project) to use the interfaces in a rigorous
way. So maybe interfaces are "programming process management" tools as well as design tools. That would be the third meaning of the "contract" aspect of interfaces.

Based on this understanding, hopefully the other interesting things about interfaces (which I don't claim to
understand well yet) will start to make more sense.
------------------------------------------------

So, that's what I think I know about interfaces. Any feedback would be appreciated.

Thanks!
 
I think the chief advantage of interfaces is polymorphism.

This simple example comes from Pattison's old book on COM. Suppose you want to define an animal. Animals move, and animals bite. So an Animal class could have two methods: Move and Bite. A client can declare an Animal variable and create a body of code to call its methods.

However, different animals move and bite in different ways. To handle this, you could instead create an iAnimal interface, with the same two methods. A client can again declare an iAnimal variable and use the same body of code to call its methods.

Now, a Flea class and a TRex class will both implement the iAnimal interface. Each one's Move and Bite methods will of course be different. (MsgBox "nip", MsgBox "CHOMP"...you get the idea.) So, an iAnimal variable can be instantiated as either a Flea or a TRex, use the same body of code to call the iAnimal methods, and vary in its behavior depending on which implementing class was instantiated.

This is polymorphism, and the advantage of it is that similar but different objects can be controlled by one body of client code.

Bob
 
I think Bob has got the basics; it provides or contributes to to the polymorhism. However, it is a bit more complex.

In C++, java and others, polymorphism is basically provided through the inheritance properties. In Bob's example, you have a generic class that bites and moves. Then you have subclasses for Flea and TRex that inherit these properties from a parent class. In this case the interface is not really necessary because inheritance is sufficient.

But now lets have another class of say Robots that also move and bite. Then need a generic class or 'Robot' and subclasses of 'K9s' and 'SpiderBods' that also move and bite.

A Flea is a subclass of 'animal', becuase of its muscles, brain, bowel etc.. A K9 is a subclass of robot, because of its servos, power supply, chips etc. Yet both need to inherit the properties of moving and biting.

This can be solved in one of two ways:

1. Make Robots and Animals subclasses of a higher class of 'Movers and Biters'. This is NOT natural and will lead to clumsy analysis.
2. Give the two parent classes a common interface, which insists that each of these two quite different parent classes have moving and biting in common.

In other words, it avoids the need (desire) to use multiple inheritance. Multiple Inheritance causes significant problems and should not be used without the express permission of the chief architect. Because of this, java doesn't allow inheritance from more than one parent so that you have to use interfaces for problems like this.

There are also many languages (normally classed as 'object based') that do NOT have inheritance. Yet they can be equally effective in implementing OO designs. Common Lisp, VB, D-com, and others that I'm less sure about. These all HAVE to use interfaces instead of inheritance for generalisation/specialisation.

Because of the 'can we use inheritance' problem, it seems to be coming more common, that Interfaces are used even where inheritance is involved in the background.

One big advantage is that Interfaces usually only allow functional access (methods). Inheritance allows both attributes and methods to be inherited and this is not usually the best approach.
It also allows the designers some greater freedom because they can use inheritance for generalisation/specialisation and interfaces for purely 'interfacing'. I'm not sure how useful this is.

This bring my answer around to the same as Bob's. It is used for polymorphism.

All the stuff I've written just shows why Inheritance, which also allows polymorphism is not always considered. This was a question I have seen asked before, so I thought I would spell it out.

Gil

 
Thanks for responding, Gil. I'm not sure I quite follow your thinking in some places, and invite you to clarify.

<polymorphism is basically provided through the inheritance properties
To me, polymorphism is based on the idea that implementations are NOT inherited from a base class; rather they are implemented in a subclass.

<In this case the interface is not really necessary because inheritance is sufficient.
I don't see how. In my example, there is no generic class that bites and moves, rather there is a generic interface that says that animals move and bite, without saying how. A flea's way of moving has nothing in common with that of a TRex (intended to be taken as a given in my example, see), and so each must implement differently. So, for example:

Flea_Move
[boing boing boing] i. e. flea's move implementation

TRex_Move
[KABOOOOMMMMM.....KABOOOOMMMM.....] trex's move implementation

Meaning, that neither of them actually use inheritance, since they don't use any implementation provided by iAnimal.

Now, I believe you're kind of showing what I'm trying to show as well, by adding in the spiderbots and so on. What you're saying is that all of these implementations have things that they do in common, although they do them differently. I'm using my flea and trex to demonstrate the same thing; the fact that my examples are flesh and blood doesn't automatically mean that they would inherit a common implementation of the move and bite methods.

<This is NOT natural and will lead to clumsy analysis.
I would qualify that to say it's a matter of context. In fact, it would be the first thing that I would consider in some situations! For example, if we had some TRex, SpiderBot and MechanoElephant objects, and we were looking at a GUI that would allow some war general to move them around on a battlefield, we might say "I just want to tell any one of them to move to a coordinate and have them do it." So, we could generalize out a "LargeWarDevice" interface, and define for it a Move method with x and y arguments. We could cause the three classes to implement the LargeWarDevice interface. Furthermore, in that context, we don't care that SpiderBots and MechanoElephants need, say, a very different sort of maintenance from TRexs.

I'd say this is a perfect example of making the animals and bots subclasses of a higher interface, and it seems quite natural to me. TRex, SpiderBot, and MechnoElephant would implement the Move method in their own ways, and some GeneralInterface program would happily instantiate LargeWarDevice objects and move them around a battlefield in the same manner for each. Polymorphism hard at work.

So, my position is that if in the context in which the superclass is used, the subclasses provide the same functionality, it makes sense to access that functionality through a common interface.

<Multiple Inheritance causes significant problems and should not be used...
Of course, there is some debate here, and I am on the same side of it as you are. For those who are unaware, the main reason that multiple inheritance creates problems is because you can have the same method defined by two different superclasses, so it's difficult for a subclass to keep track of which implementation it is using. Now, obviously, this is not a problem with interfaces. If two interfaces specify the same method, they still don't provide any implementation of their own. A single implementation in the subclass of the doubly-defined method satisfies the requirement of each of the interfaces that that method be implemented. That's why Java allows multiple interface implementations but not multiple inheritance.

<Interfaces are used even where inheritance is involved in the background.
I don't understand what you mean here. Can you explain a bit what you mean by "in the background"?

<Inheritance, which also allows polymorphism
As I see it, the only way to get polymorphism from inheritance is to override methods or provide abstract methods. Is this what you are getting at?

Bob
 
That is a big question :-(

Your last sentence says it all
"As I see it, the only way to get polymorphism from inheritance is to override methods or provide abstract methods." I thought you were saying that 'Interfaces' were the only way.

The rest of my discussion was trying to establish when to use polymorphism through interfaces and when to use polymorphism through inheritance. The latter is slightly more flexible but also more dangerous if your language allows multiple inheritance. Interfaces are safer and simpler.

Given this, I think we are saying the same thing. It is too much to cover each point sepparately, so I'm leaving it at that.

Sorry, I rushed my story and added more confusion than clarity.

Gil
 
<I thought you were saying that 'Interfaces' were the only way.

Well, no, they're the only RIGHT way. :p

Seriously, I get what you're saying now. It seems to me that using inheritance to achieve polymorphism is most typical in abstract classes, where some functionality is implemented in a base class and some not. The polymorphic behavior would typically be in the abstract methods. On the other hand, overriding implementations can be fine too; an obvious example would be overriding the ToString method of the .Net System.Object. You might use the default implementation and you might use an overriding implementation and get polymorphic behavior that way.

Anyway, it's a good point to make, Gil, that interfaces are NOT the only way to accomplish polymorphism. I can see where my opening statement implied that, and didn't mean to.

Bob

 
Another aspect of Interfaces is information hiding, and therefore making code analysis more easy.

Think of a 'Robot'-class, which implements 'moveable'.
Another class is interested in moving the robot around.
Let's call it 'MoveController'.

You could pass the Robot to the MoveController to let it be controlled.
If someone looks at the code, he might need some time, to find out, that the only method of Robot, which is called by MoveController, is 'move'.
If the Interface defines 'move' to be the only method, you would see this design-decision, if 'MoveController' would only expect 'Moveables', not something specific from Robot.

You gain this benefit without before using multi-inheritance. Foreign classes only get access to a well choosen part of another.
If something isn't working as expected in Robot, you know that 'MoveController' might only call 'move' and not cause problems somewhere else.

There are voices, which claim concrete inheritance to be a language-defect of java with good reasons, but I'm not sure whether to follow - it looks a bit rigorous to me.
I'm a bit new to this debate to make a clear decision.

seeking a job as java-programmer in Berlin:
 
<information hiding
Often called "encapsulation"

<claim concrete inheritance to be a language-defect of java with good reasons
What are those reasons?

Bob
 
Thanks for the articles, stefan. I personally prefer to use interfaces for the most part, although I believe there's a place for implementation inheritance as well.

Bob
 
The whole thing is disarmingly simple ... "what, not how."

When you envision the interface of anything, think in terms of "what" you want to do, or "what" you want to know. When you write the code, your goal is to write "how" each request is to be accomplished.

There is, unfortunately, a very serious thorn in this sweet smelling rose... and that thorn, seldom discussed by the academics who write textbooks rather than production code, is functional dependency that is introduced by the very same "class inheritance" structure that is routinely presented as The Solution. When you express a "Platypus" as being a descendent of "Animal," there's no serious problem in defining, say, an "Armadillo" as a new leaf to this taxonomy, but what if a new change (coming thirteen years into the life of the application and after the definition of 1,422 different classes by eighteen different programmers, only one of whom works here and three of whom are dead...) must be applied, say, to Animal? Or to something in-between? Now you either have a change that could "ripple down" to 1,422 test-cases, or you have an equal number of individual changes to consider.

So, while you can and should try to design the strongest code that you can, don't be too clever. The application-lifetime, number-of-changes, number of programmers (and the fates thereof), that I somewhat whimsically described is quite realistic in the world of production data-processing ... Try to be economical in your design, but also plan for change. Try to be as nice as you can to the programmers who will follow you.
 
SundialServices said:
... don't be too clever.
I'm not sure what you mean by "too clever"?

The example you gave is one example where deriving from a concrete Animal base class would be better than an Animal interface. That way you could add new functions to Animal without breaking all the sub-classes. If you added an abstract function, all sub-classes would have to implement the new function. Not that there's anything wrong with interfaces... You just need to be careful about making changes to an interface.
 
I tend to think of interfaces as types. By implemented an interface in a class, you are making your class that particular type.

For example, I had to develop an application where all of the text in the UI had to be translatable into different languages. The way I did this was to create an interface called ITranslatable. This has a method on it which translated the controls displayed text. I then extended each control that needed to be translatable (labels, buttons etc) and implemented the ITranslatable interface. I could then implement the actual machanics of the translation in a way that is appropriate for each control.

I used a page base class in the application (abtract inheritance here!) which contained a method that performed the translations each time the page was loaded. The method drilled down through all of the controls on the page. When it encountered a ITranslatable control, it ran the Translate method on it to translate the text of the control. The base class method had no need to know aything about the control, other than it was of type ITranslatable. It had no need to know anything about how the actual translation was implemented for each control.

Once this was set up, whenever I created a new page all I had to do was extend it from the page base class, and use the extended Translatable controls that I created. If this was done, then no further action was required to make the page translate, so long as the relevant texts were available in the right place.

Hope this makes sense!
 
cpjust said:
SundialServices said:
... don't be too clever.
I'm not sure what you mean by "too clever"?
I'm pretty sure what he means is to apply the KISS principle at all levels of abstraction.

I once worked with a guy who whever a new release of the language came out, he just had to figure out a way to use every single new feature. It pretty much made his code unmaintainable - people who came after him had to spend time ripping all that purposeless stuff out, and making the code more straight-forward.

Chip H.

____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
<The example you gave is one example where deriving from a concrete Animal base class would be better than an Animal interface.

I wouldn't go that far. It's more a matter of where you take the risk. If you go with concrete inheritance, you still take the risk that you may one day need to change the implementation of some part of the Animal class (so-called "fragile base class problem"), which could have a ripple effect on all inherited classes.

So, you describe well the problems that can accrue by making redefinitions of abstract base classes, but it's just as much a problem to make reimplementations of the underlying code in concrete base classes.

In other words, I'm not saying that there's anything wrong with concrete inheritance, you just have to be careful about making changes to a base class. :)

Bob
 
BobRodes said:
... you still take the risk that you may one day need to change the implementation of some part of the Animal class (so-called "fragile base class problem"), which could have a ripple effect on all inherited classes.
Changing the implementation isn't much of a problem, as long as it still does what it was intended to do. It's when you change the interface of a base class that you start to break things.
 
Let me put it another way... just take it all as a cautionary tale...

The basic description of an "Animal" has not changed since Whomever did it in However-Many days. The taxonomy of Animals is also very distinct: with the exception of what Charles Darwin claims to have oberved, "Animals" do not change. You are describing a nice, static situation.

If only the real-world of business data processing were quite so nice and static! And since it isn't, this necessitates a certain amount of deviation from the idealistic rules that are espoused in the college classroom. You must, in a word, anticipate unforseen change.

If you build a simple taxonomy ... perfectly valid for the way that things are now... then you have also created a web of functional dependency that can be difficult or even impossible to untangle whenever one of these "unforseen changes" happens. (We don't know what the change is, but we know that it will from time to time happen.) Changes to this taxonomy can "ripple" throughout the entire structure.

Another "cautionary tale" is this: when you get out of the classroom and into real-life, there will be mountains of existing code out there, some of it written when your father was your age, that still runs the business and still works in persnikety ways, and which imposes modifications to your pristine designs. It bears remembering that, in its day, that code was also "pristine" and that what you see today reflects the thousands of changes, bug-fixes, enhancements, business-strategy adjustments and so-on that have happened since that original DATE-WRITTEN. (Reference to COBOL...) In due time, that sort of thing will necessarily happen to this code! There are serious questions about how well this "new style of coding" will prove to be able to bear up to such changes!

 
Ideally, you would refactor code as you make modifications over time. Your automated unit tests then give you the confidence that you aren't breaking stuff.

In the real world, seldom do development organizations have the discipline needed to do all that. And so you end up with ISAM records where the customer name is split across three byte sequences ("we need a longer custname field - find some room without extending the record size!")

Chip H.


____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top