查看组合和继承的更广泛的方式是,组合是一种实现 has-a 关系的设计技术,而继承是一种实现 is-a 关系的技术.让我们进入面向对象的角度来更好地理解这一点。
当我说Dog 是一个 Mammal 和Snake 是一个 Reptile 但两者都是Animals,设计可以像,应该有一个名为Animal 的超类和两个名为Mammal 和Reptile 的子类,其中Dog 和Snake 应该被扩展。相应代码如下:
public abstract class Animal {
public abstract void move();
public abstract void sleep();
public abstract void reproduce();
}
任何动物都可以执行这三个动作。
public abstract class Mammal extends Animal{
@Override
public void reproduce(){
System.out.println("Gives birth!!");
}
}
public abstract class Reptile extends Animal{
@Override
public void reproduce(){
System.out.println("Lays Eggs!!");
}
}
所有哺乳动物/爬行动物都会以共同的方式执行这个定义的功能。
public class Dog extends Mammal{
@Override
public void move() {
System.out.println("Uses it's limbs");
}
@Override
public void sleep() {
System.out.println("Sleeps on it's tummy");
}
}
public class Snake extends Reptile{
@Override
public void move() {
System.out.println("Crawls");
}
@Override
public void sleep() {
System.out.println("");
}
}
正如您在此示例中所看到的,Dog 扩展了 Mammal 和 Snake 扩展了 Reptile。因此,在任何给定时间点,Dog 将永远是 Mammal 和Snake 将永远是 Reptile。因此,这种is-a 关系在两个实体之间建立了strong bond。在执行过程中,只要Dog扩展Mammal,就不能是Reptile或其他任何东西。
回到 has-a 关系(组合),我可以说 Person has-a Car。我没有指定此人拥有的Car 的类型。让我们回到面向对象的角度来更好地理解这一点。
考虑这个Person 类
public class Person {
private String name;
private String address;
private Car car;
public Person(String name, String address, Car car) {
super();
this.name = name;
this.address = address;
this.car = car;
}
}
这里可以看出,一个Person有一个名字、地址和汽车。
Car 和相关类的代码如下:
public class Car {
//Car related methods
}
public class Ferrari extends Car{
//Ferrari specific methods, attributes
}
public class Bmw extends Car{
//BMW specific attributes, methods.
}
可以看出BMW和Ferrari是Car的类型。
现在回到声明“Person has-a Car”,Car 可以是任何 Car。它可能是法拉利或宝马或其他任何东西。这可以在创建Person 对象时传入。
Person john = new Person("John", "#81, 2nd Street,..", new Ferrari());
可以看出,John 接受了一个Ferrari Car。在这里,John 可以接收在对象创建期间传递的任何类型的Car(动态性质)。因此,这种级别的灵活性是由 has-a(组合)关系提供的。
我希望这能消除您的疑虑。