Inheritance and interfaces

2019-07-17 15:28发布

This is somewhat of a follow-up question to this question.

Suppose I have an inheritance tree as follows:

Car -> Ford -> Mustang -> MustangGT

Is there a benefit to defining interfaces for each of these classes? Example:

ICar -> IFord -> IMustang -> IMustangGT

I can see that maybe other classes (like Chevy) would want to implement Icar or IFord and maybe even IMustang, but probably not IMustangGT because it is so specific. Are the interfaces superfluous in this case?

Also, I would think that any class that would want to implement IFord would definitely want to use its one inheritance by inheriting from Ford so as not to duplicate code. If that is a given, what is the benefit of also implementing IFord?

14条回答
我命由我不由天
2楼-- · 2019-07-17 15:56

You shouldn't implement any of those interfaces at all.

Class inheritance describes what an object is (eg: it's identity). This is fine, however most of the time what an object is, is far less important than what an object does. This is where interfaces come in.

An interface should describe what an object does), or what it acts like. By this I mean it's behavior, and the set of operations which make sense given that behaviour.

As such, good interface names should usually be of the form IDriveable, IHasWheels, and so on. Sometimes the best way to describe this behaviour is to reference a well-known other object, so you can say "acts like one of these" (eg: IList) but IMHO that form of naming is in the minority.

Given that logic, the scenarios where interface inheritance makes sense are completely and entirely different from the scenarios where object inheritance makes sense - often these scenarios don't relate to eachother at all.

Hope that helps you think through the interfaces you should actually need :-)

查看更多
够拽才男人
3楼-- · 2019-07-17 15:56

I'd say only make an interface for things you need to refer to. You may have some other classes or functions that need to know about a car, but how often will there be something that needs to know about a ford?

查看更多
再贱就再见
4楼-- · 2019-07-17 15:58

Think carefully about how your objects need to interact with each other within your problem domain, and consider if you need to have more than one implementation of a particular abstract concept. Use Interfaces to provide a contract around a concept that other objects interact with.

In your example, I would suggest that Ford is probably a Manufacturer and Mustang is a ModelName Value used by the Manufacturer Ford, therefore you might have something more like:

IVehichle -> CarImpl, MotorbikeImpl - has-a Manufacturer has-many ModelNames

查看更多
倾城 Initia
5楼-- · 2019-07-17 16:02

In this answer about the difference between interface and class, I explained that:

  • interface exposes what a concept is (in term of "what is" valid, at compilation time), and is used for values (MyInterface x = ...)
  • class exposes what a concept does (actually executed at runtime), and is used for values or for objects (MyClass x or aMyClass.method() )

So if you need to store into a 'Ford' variable (notion of 'value') different sub-classes of Ford, create an IFord. Otherwise, do not bother until you actually need it.

That is one criteria: if it is not met, IFord is probably useless.
If it is met, then the other criteria exposed in the previous answers apply: If a Ford has a richer API than a Car, an IFord is useful for polymorphisms purpose. If not, ICar is enough.

查看更多
淡お忘
6楼-- · 2019-07-17 16:03

I also agree with adamalex's response that interfaces should be shared by classes that should respond to certain methods.

If classes have similar functionality, yet are not directly related to each other in an ancestral relationship, then an interface would be a good way to add that function to the classes without duplicating functionality between the two. (Or have multiple implementations with only subtle differences.)

While we're using a car analogy, a concrete example. Let's say we have the following classes:

Car -> Ford   -> Escape  -> EscapeHybrid
Car -> Toyota -> Corolla -> CorollaHybrid

Cars have wheels and can Drive() and Steer(). So those methods should exist in the Car class. (Probably the Car class will be an abstract class.)

Going down the line, we get the distinction between Ford and Toyota (probably implemented as difference in the type of emblem on the car, again probably an abstract class.)

Then, finally we have a Escape and Corolla class which are classes that are completely implemented as a car.

Now, how could we make a Hybrid vehicle?

We could have a subclass of Escape that is EscapeHybrid which adds a FordsHybridDrive() method, and a subclass of Corolla that is CorollaHybrid with ToyotasHybridDrive() method. The methods are basically doing the same thing, but yet we have different methods. Yuck. Seems like we can do better than that.

Let's say that a hybrid has a HybridDrive() method. Since we don't want to end up having two different types of hybrids (in a perfect world), so we can make an IHybrid interface which has a HybridDrive() method.

So, if we want to make an EscapeHybrid or CorollaHybrid class, all we have to do is to implement the IHybrid interface.

For a real world example, let's take a look at Java. A class which can do a comparison of an object with another object implements the Comparable interface. As the name implies, the interface should be for a class that is comparable, hence the name "Comparable".

Just as a matter of interest, a car example is used in the Interfaces lesson of the Java Tutorial.

查看更多
Bombasti
7楼-- · 2019-07-17 16:03

In general, the best way to think about this (and many questions in OO) is to think about the notion of a contract.

A contract is defined as an agreement between two (or more) parties, that states specific obligations each party must meet; in a program, this is what services a class will provide, and what you have to provide the class in order to get the services. An interface states a contract that any class implementing the interface must satisfy.

With that in mind, though, your question somewhat depends on what language you're using and what you want to do.

After many years of doing OO (like, oh my god, 30 years) I would usually write an interface for every contract, especially in Java, because it makes tests so much easier: if I have an interface for the class, I can build mock objects easily, almost trivially.

查看更多
登录 后发表回答