tshad said:
Hopefully you are still taking the example with a grain of salt.
I am curious about something in the program.
The interface it uses is IAnimal. So everything that inherits from IAnimal
must have a MakeSound Method.
public interface IAnimal
{
string MakeSound();
}
True. However, IMHO the sample code has a basic design problem. That
is, in using every-day words it creates a false hierarchy. This is
compounded by what is in my opinion imprecise use of the term "inherits"
on your part.
In particular, I prefer to describe an interface as being "implemented"
by a class, rather than "inherited". To me, "inherited" implies that
the class actually gets some already-implemented functionality.
Obviously this is not the case for interfaces.
Likewise, in C# a class can only directly inherit one other class. So
what does it mean for a class to "inherit" multiple interfaces? I
understand that one really means it implements multiple interfaces, but
IMHO one should be precise about saying that instead.
This imprecision might not be so bad, except that in the example code
from that blog, it's my opinion that IAnimal is a bad interface. There
should instead be an "Animal" base class that actually _is_ inherited.
This theoretical "Animal" class would _implement_ basic behaviors that
all animals share.
As an example of an interface, I might create a "IVocalize" interface,
which would contain the "MakeSound()" method. Not all animals do make
sounds, and so by doing it this way, all animals would have a common
shared base class "Animal" that really is universal to all animals,
while those that can intentionally make sounds would _implement_ the
"IVocalize" interface themselves in whatever way was appropriate to that
particular animal.
(Ignoring for the moment the biological issue that for all we know,
_all_ animals do in fact intentionally make sounds, and the only true
division is "those that we know make sounds, and those that make sounds
but which we don't actually know about". Who knows? Maybe it'll turn
out that even bacteria and amoebas make sounds
).
IMHO, viewing it that way makes it much more clear the difference
between an interface and an inherited class.
Finally, while I think that others have already touched on this, I'll
respond to your question "And if I have to implement all the functions
described in the Interface, what am I really inheriting? Why not just
use an abstract class to do this?"
The answer to "what am I really inheriting?" is that you are not
inheriting _anything_ when you use an interface. You are declaring in
your class an agreement to fulfill a specific contract, to define
certain elements as part of your class so that other code can look at
your class and be assured that it _implements_ those elements.
If you want to _inherit_ some implementation, then you need to use an
actual class that defines that implementation. But in C# you can only
inherit one class, so choose that class wisely.
An abstract class performs double-duty as an inheritable implementation
with some abstract elements. If the abstract class contains _only_
abstract declarations, then it would probably be better to define it as
an interface. The exception would be if you really want to restrict
inheritors so that they cannot inherit any other class. But I think
that a design where that restriction is actually desirable probably
doesn't come up that often.
An abstract class that does provide some implementation is sort of the
best (and worst
) of both worlds. You get to inherit that basic
implementation, while also being provided a contract that your own class
is required to implement, fulfilling the complete API described by the
abstract class.
You had some other specific questions about the blog code sample, so...
[...]
One question is: Why don't they have ToString() as part of the Interface?
ToString() is part of the Object class definition. Object provides a
default implementation, so all classes already have ToString(). If you
want to override the default behavior in your own class, you may.
There's no need for any interfaces to also include it though.
This is related to your apparent misunderstanding of the difference
between inheriting a class and implementing an interface. In the
example code, Cat doesn't inherit IAnimal, it implements it. Cat _does_
inherit Object (all classes do, whether explicitly declared that way or
not), and so it already has a ToString() method.
Is the reason for having the IAnimal interface just so they can force a
method?
The reason for having "IAnimal" is to declare a specific set of methods
(in this case, just one) that a class promises to implement. That way,
other code can ask for something that's just an "IAnimal" without caring
what class it actually is. That other code only is interested in the
behavior defined in "IAnimal", and so that's the interface implemented
by any other classes that want to work with the code that needs an
"IAnimal".
Also, what is the difference between the animal classes that inherited from
IAnimal:
public class Cat : IAnimal
and this class that IS IAnimal?
public class AnimalFactory
{
public static IAnimal GetAnimal(string key)
{
[...code snipped...]
}
}
This was confusing to me.
I hope I've already been clear that Cat doesn't inherit IAnimal.
However, I also want to point out that the class AnimalFactory is also
definitely _not_ an IAnimal, nor is it true that the method GetAnimal
"is IAnimal". The method returns an instance of an object that
implements the IAnimal interface; that's all. The method itself is not
an IAnimal, nor is it any kind of class or interface at all. It's a method.
In the case of the animals they were not an IAnimal class but a bird or cat
class and had to have MakeSound() method. But the above GetAnimal() method
IS an IAnimal Class and doesn't have the MakeSound() method.
Nope. The method is not an IAnimal. There's no such thing as an
IAnimal class in the example code, so it definitely can't be "an IAnimal
Class". But it also isn't anything that _could_ be a class or _could_
implement an interface. Only classes can do that. A method is just
that: a method. A method can't have another method in C#, not could it
implement an interface, nor could it be treated as a class.
[...]
You may need to post a working sample, because you're asking the group to
evaluate...your evaluation... of another person's code.
So its hard to see what he is doing.
My mistake.
I was planning on pasting it in but must have forgot to paste it in.
Thanks for the code. It makes it much easier to understand your
original question.
Now, as far as the specific interfaces go...
In both cases, the interfaces are declaring some specific behavior that
a given class can promise, by declaration, to implement. In this case,
the Student class declares that it implements IComparable and IDisplayable.
In doing so, it essentially enters into a contract with any code that
might use an instance of a Student that it will implement the methods in
those interfaces: IComparable.CompareTo() and IDisplayable.GetString().
By doing so, other code can use the Student instance without knowing
that it's a Student at all. All that other code needs to know is the
interface it's implemented.
So, there one place where the code only needs to know that the instances
are comparable, so that it can sort them. Thus that code treats the
Student as an IComparable, and because Student implements that
interface, it can be sorted, without the code doing the sorting knowing
anything else about the class.
Likewise, IDisplayable. There's code that wants to be able to display
the instance somehow using a string value, without caring about anything
else about the class other than it can return a string for display purposes.
In the example code, there are then two completely different, unrelated
classes that both implement both interfaces. And then there's code that
performs some work on class instances, but only by using the declared
interfaces. By doing so, that code can handle both the Student
instances and the Bird instances without knowing anything about those
classes except the specific interface those classes implement and which
are required for the specific operation.
One thing I don't particularly like about the example is that the
IDisplayable interface seems redundant to me, since in C# all objects
already inherit Object which has ToString(). There's nothing wrong with
the code per se, but it seems to me that the example would be more clear
if it had defined an interface that didn't overlap an existing language
feature.
Pete