When to implement an interface and when to extend a superclass?
I've been reading a lot about interfaces and class inheritance in Java, and I know how to do both and I think I have a good feel for both. But it seems that nobody ever really compares the two side by side and explains when and why you would want to use one or the other. I have not found a 开发者_如何学Pythonlot of times when implementing an interface would be a better system than extending a superclass.
So when do you implement an interface and when do you extend a superclass?
Use an interface if you want to define a contract. I.e. X must take Y and return Z. It doesn't care how the code is doing that. A class can implement multiple interfaces.
Use an abstract class if you want to define default behaviour in non-abstract methods so that the endusers can reuse it without rewriting it again and again. A class can extend from only one other class. An abstract class with only abstract methods can be as good definied as an interface. An abstract class without any abstract method is recognizeable as the Template Method pattern (see this answer for some real world examples).
An abstract class in turn can perfectly implement an interface whenever you want to provide the enduser freedom in defining the default behaviour.
You should choose an interface if all you want is to define a contract i.e. method signatures that you want the inheriting classes to implement. An interface can have no implementation at all. The inheriting classes are free to choose their own implementation.
Sometimes you want to define partial implementation in a base type and want to leave the rest to inheriting classes. If that is the case, choose an abstract class. An abstract class can define method implementations and variables while leaving some methods as abstract. Extending classes can choose how to implement the abstract methods while they also have the partial implementation provided by the superclass.
One extreme of abstract classes is a pure abstract class - one that has only abstract methods and nothing else. If it comes to pure abstract class vs. an interface, go with the interface. Java allows only single implementation inheritance whereas it allows multiple interface inheritance meaning that a class can implement multiple interfaces but can extend only one class. So choosing a pure abstract class over the interface will mean that the subclass will not be allowed to extend any other class while implementing the abstract methods.
Use an interface to define behavior. User (abstract) classes (and subclasses) to provide implementation. They are not mutually exclusive; they can all work together.
For example, lets say you are defining a data access object. You want your DAO to be able to load data. So put a load method on the interface. This means that anything that wants to call itself a DAO must implement load. Now lets say you need to load A and B. You can create a generic abstract class that is parameterized (generics) to provide the outline on how the load works. You then subclass that abstract class to provide the concrete implementations for A and B.
No one?
http://mindprod.com/jgloss/interfacevsabstract.html
EDIT: I should supply more than a link
Here's a situation. To build on the car example below, consider this
interface Drivable {
void drive(float miles);
}
abstract class Car implements Drivable {
float gallonsOfGas;
float odometer;
final float mpg;
protected Car(float mpg) { gallonsOfGas = 0; odometer = 0; this.mpg = mpg; }
public void addGas(float gallons) { gallonsOfGas += gallons; }
public void drive(float miles) {
if(miles/mpg > gallonsOfGas) throw new NotEnoughGasException();
gallonsOfGas -= miles/mpg;
odometer += miles;
}
}
class LeakyCar extends Car { // still implements Drivable because of Car
public addGas(float gallons) { super.addGas(gallons * .8); } // leaky tank
}
class ElectricCar extends Car {
float electricMiles;
public void drive(float miles) { // can we drive the whole way electric?
if(electricMiles > miles) {
electricMiles -= miles;
odometer += miles;
return; // early return here
}
if(electricMiles > 0) { // exhaust electric miles first
if((miles-electricMiles)/mpg > gallonsOfGas)
throw new NotEnoughGasException();
miles -= electricMiles;
odometer += electricMiles;
electricMiles = 0;
}
// finish driving
super.drive(miles);
}
}
The main reason for using abstract classes and interfaces are different.
An abstract class should be used when you have classes that have identical implementations for a bunch of methods, but vary in a few.
This may be a bad example, but the most obvious use of abstract classes in the Java framework is within the java.io classes. OutputStream
is just a stream of bytes. Where that stream goes to depends entirely on which subclass of OutputStream
you're using... FileOutputStream
, PipedOutputStream
, the output stream created from a java.net.Socket
's getOutputStream
method...
Note: java.io also uses the Decorator pattern to wrap streams in other streams/readers/writers.
An interface should be used when you just want to guarantee that a class implements a set of methods, but you don't care how.
The most obvious use of interfaces is within the Collections framework.
I don't care how a List
adds/removes elements, so long as I can call add(something)
and get(0)
to put and get elements. It may use an array (ArrayList
, CopyOnWriteArrayList
), linked list (LinkedList
), etc...
The other advantage in using interfaces is that a class may implement more than one. LinkedList
is an implementation of both List
and Deque
.
I think that interfaces work best when you use them to express that the object has a certain property or behavior, that spans multiple inheritance trees, and is only clearly defined for each class.
For example think of Comparable. If you wanted to create a class Comparable to be extended by other classes, it would have to be very high on the inheritance tree, possible right after Object, and the property it expresses is that two objects of that type can be compared, but there's no way to define that generally (you can't have an implementation of compareTo directly in the Comparable class, it's different for every class that implements it).
Classes work best when they define something clear, you know what properties and behaviors they have, and have actual implementations for methods, that you want to pass down to the children.
So classes work when you need to define a concrete object like a human, or a car, and interfaces work better when you need more abstract behavior that's too general to belong to any inheritance tree, like the ability to be compared (Comparable) or to be run (Runnable).
One method of choosing between an interface
and a base class
is the consideration of code ownership. If you control all the code then a base class is a viable option. If on the other hand many different companies might want to produce replaceable components, that is define a contract then an interface is your only choice.
I found some articles, particularly some who describe why you should not use implementation inheritance (i.e. superclasses):
- Why extends is evil
- Inheritance of implementation is evil
- Implementation inheritance
- Implementation inheritance
- Java inheritance FAQ
I guess I'll give the classic car example.
When you have a car interface, you can create a Ford, a Chevy, and an Oldsmobile. In other words, you create different kinds of cars from a car interface.
When you have a car class, you can then extend the car class to make a truck, or a bus. In other words, you add new attributes to the sub classes while keeping the attributes of the base or super class.
You can think of extending from a super class if the derived class is of the same type.I mean that when a class extends an abstract class, they both should be of the same type, the only difference being that the super class has a more general behavior and the sub class has a more specific behavior. An interface is a totally different concept. When a class implements an interface, its either to expose some API(contract) or to get certain behavior. To give an example, I would say that Car is an abstract class. You can extend many classes from it like say Ford, Chevy and so on which are each of type car. But then if you need certain specific behavior like say you need a GPS in a car then the concrete class, eg Ford should implement GPS interface.
If you only want to inherit method signatures (name, arguments, return type) in the subclasses, use an interface, but if you also want to inherit implementation code, use a superclass.
精彩评论