Serious Polymorphism: Class Abstract dan Interface
Designing with inheritance
Did we forget about something when we designed this?
The class structure isn't too bad. We've designed it so that duplicate code is kept to a minimum, and we've overridden the methods that we think should have subclass specific implementations. We've made it nice and flexible from a polymorphic perspective, because we can design Animal using programs with animal arguments (and array declarations), so that any animal subtype – including those we never imagined at the time we wrote our code – can be passed in and used at run time. we've put the common protocol for all animals (the four methods that we want the world to know all Animals have) in the Animal superclass, and we're ready to start making new Lions and Tigers and Hippos.
What does a new Animal() object look like?
What are the instance variable values?
Some classes just should not be instantiated!
It makes sense to create a wolf object or a hippo object or a tiger object, but what exactly is an animal object? what shape is it? What colour, size, number of legs... Trying to create an object of type animal is like a nightmare StarTrektm transporter accident. The one where somewhere in the beam-me-up process something bad happened to the buffer.
But how do we deal with this? we need an animal class, for inheritance and polymorphism. But we want programmers to instantiate only the less abstract subclasses of class animal, not animal itself. we want tiger objects and lion objects, not animal objects.
Fortunately, there's a simple way to prevent a class from ever being instantiated. In other words, to stop anyone from saying "new" on that type. by marking the class as abstract, the compiler will stop any code, anywhere, from ever creating an instance of that type.
You can still use that abstract type as a reference type. in fact, that's a big part of why you have that abstract class in the first place (to use it as a polymorphic argument or return type, or to make a polymorphic array).
When you're designing your class inheritance structure, you have to decide which classes are abstract and which are concrete. concrete classes are those that are specific enough to be instantiated. A concrete class just means that it's ok to make objects of that type.
Making a class abstract is easy – put the keyword abstract before the class declaration:
abstract class Canine extends Animal {
public void roam() {
}
}
The compiler won’t let you instantiate an abstract class
An abstract class means that nobody can ever make a new instance of that class. You can still use that abstract class as a declared reference type, for the purpose of polymorphism, but you don't have to worry about somebody making objects of that type. The compiler guarantees it.
Abstract vs. Concrete Class
A class that's not abstract is called a concrete class. in the animal inheritance tree, if we make animal, canine, and feline abstract, that leaves Hippo, Wolf, Dog, Tiger, Lion, and Cat as the concrete subclasses. Flip through the Java API and you'll find a lot of abstract classes, especially in the GUI library. What does a GUI Component look like? The component class is the superclass of GUI-related classes for things like buttons, text areas, scrollbars, dialog boxes, you name it. you don't make an instance of a generic component and put it on the screen, you make a JButton. In other words, you instantiate only a concrete subclass of component, but never component itself.
abstract or concrete?
How do you know when a class should be abstract? wine is probably abstract. But what about red and white? Again, probably abstract (for some of us, anyway). but at what point in the hierarchy do things become concrete? Do you make Pinot Noir concrete, or is it abstract too? it looks like the Camelot Vineyards 1997 Pinot Noir is probably concrete no matter what. but how do you know for sure?
Look at the animal inheritance tree above. do the choices we've made for which classes are abstract and which are concrete seem appropriate? would you change anything about the animal inheritance tree (other than adding more animals, of course)?
Abstract methods
Besides classes, you can mark methods abstract, too. an abstract class means the class must be extended; an abstract method means the method must be overridden. You might decide that some (or all) behaviors in an abstract class don't make any sense unless they're implemented by a more specific subclass. in other words, you can't think of any generic method implementation that could possibly be useful for subclasses. what would a generic eat() method look like?
An abstract method has no body!
Because you've already decided there isn't any code that would make sense in the abstract method, you won't put in a method body. So, no curly braces–just end the declaration with a semicolon.
If you declare an abstract method, you MUST mark the class abstract as well. You can’t have an abstract method in a non-abstract class.
If you put even a single abstract method in a class, you have to make the class abstract. But you can mix both abstract and non-abstract methods in the abstract class.
You MUST implement all abstract methods
Implementing an abstract method is just like overriding a method.
Abstract methods don’t have a body. they exist solely for polymorphism. That means the first concrete class in the inheritance tree must implement all abstract methods.
You can, however, pass the buck by being abstract yourself. If both animal and canine are abstract, for example, and both have abstract methods, class Canine does not have to implement the abstract methods from Animal. But as soon as we get to the first concrete subclass, like Dog, that subclass must implement all of the abstract methods from both Animal and Canine.
But remember that an abstract class can have both abstract and non-abstract methods, so Canine, for example, could implement an abstract method from Animal, so that Dog didn’t have to. but if Canine says nothing about the abstract methods from Animal, dog has to implement all of Animal’s abstract methods.
When we say “you must implement the abstract method”, that means you must provide a body. That means you must create a non-abstract method in your class with the same method signature (name and arguments) and a return type that is compatible with the declared return type of the abstract method. what you put in that method is up to you. All java cares about is that the method is there, in your concrete subclass.
Polymorphism examples, Polymorphism in action
Let’s say that we want to write our own kind of list class, one that will hold Dog objects, but pretend for a moment that we don’t know about the ArrayList class. for the first pass, we’ll give it just an add() method. We’ll use a simple dog array (Dog[]) to keep the added dog objects, and give it a length of 5. When we reach the limit of 5 dog objects, you can still call the add() method but it won’t do anything. If we’re not at the limit, the add() method puts the Dog in the array at the next available index position, then increments that next available index (nextIndex).
Now we need to keep Cats, too
We have a few options here:
Make a separate class, MyCatList, to hold Cat objects. pretty chunky.
Make a single class, DogAndCatList, that keeps two different arrays as instance variables and has two different add() methods: addCat(Cat c) and addDog(Dog d). another chunky solution.
Make heterogeneous AnimalList class, that takes any kind of Animal subclass (since we know that if the spec changed to add Cats, sooner or later we'll have some other kind of Animal added as well). We like this option best, so let’s change our class to make it more generic, to take Animals instead of just Dogs. We’ve highlighted the key changes (the logic is the same, of course, but the type has changed from Dog to Animal everywhere in the code.
The ultimate superclass: Object
What about non-Animals? Why not make a class generic enough to take anything?
So, what’s in this ultra-super-mega class Object?
Object & Abstract Class
Using polymorphic references of type Object has a price...
When a Dog loses its Dogness
Interfaces and polymorphism
objects are Objects
Multiple inheritance?
So, what we REALLY need is:
A way to have pet behavior in just the pet classes
A way to guarantee that all pet classes have all of the same methods defined (same name, same arguments, same return types, no missing methods, etc.), without having to cross your fingers and hope all the programmers get it right.
A way to take advantage of polymorphism so that all pets can have their pet methods called, without having to use arguments, return types, and arrays for each and every pet class.
There’s just one problem with the “two superclasses” approach...
Interfaces
Java gives you a solution. an interface. not a GUI interface, not the generic use of the word interface as in, “That's the public interface for the button class API,” but the java keyword interface.
A java interface solves your multiple inheritance problem by giving you much of the polymorphic benefits of multiple inheritance without the pain and suffering from the deadly diamond of death (DDD).
The way in which interfaces side-step the DDD is surprisingly simple: make all the methods abstract! that way, the subclass must implement the methods (remember, abstract methods must be implemented by the first concrete subclass), so at runtime the JVM isn’t confused about which of the two inherited versions it’s supposed to call.
Making and Implementing the Pet interface
Interface polymorphism
Using super
Invoking the superclass version of a method
Comments
Post a Comment