为什么喜欢构图而不是继承呢?每种方法都有哪些权衡取舍?什么时候应该选择继承而不是作文?
首选组合而不是继承,因为它更具延展性 / 易于修改,但不使用 compose-always 方法。通过组合,可以使用依赖注入 / 设置器轻松更改行为。继承更加严格,因为大多数语言不允许您从多个类型派生。因此,一旦你从 TypeA 派生,鹅就会或多或少地煮熟。
我对上述的酸测试是:
例如,塞斯纳双翼飞机将暴露飞机的完整界面,如果不是更多。因此,它适合从飞机派生。
例如,鸟可能只需要飞机的飞行行为。在这种情况下,将其作为接口 / 类 / 两者提取出来并使其成为两个类的成员是有意义的。
更新:刚回到我的答案,现在看来,如果不特别提及芭芭拉利斯科夫的利斯科夫替代原则作为 “我是否应该继承这种类型?” 的测试,它似乎是不完整的。
将遏制视为一种关系。汽车 “有一个” 引擎,一个人 “有一个” 的名字等。
想继承的作为是有关系的。汽车 “是” 汽车,人是 “哺乳动物” 等。
我不相信这种方法。我直接从Steve McConnell的第二版 Code Code 中直接看到了第 6.3 节 。
如果您了解其中的差异,则更容易解释。
这方面的一个例子是没有使用类的 PHP(特别是在 PHP5 之前)。所有逻辑都在一组函数中编码。您可以包含其他包含帮助程序函数的文件,并通过在函数中传递数据来执行您的业务逻辑。随着应用程序的增长,这可能非常难以管理。 PHP5 试图通过提供更多面向对象的设计来解决这个问题。
这鼓励使用课程。继承是 OO 设计的三个原则之一(继承,多态,封装)。
class Person {
String Title;
String Name;
Int Age
}
class Employee : Person {
Int Salary;
String Title;
}
这是工作中的继承。员工 “是” 人或继承人。所有继承关系都是 “is-a” 关系。 Employee 还会从 Person 隐藏 Title 属性,这意味着 Employee.Title 将返回 Employee 的 Title 而不是 Person。
组合比继承更受青睐。简单地说,你会有:
class Person {
String Title;
String Name;
Int Age;
public Person(String title, String name, String age) {
this.Title = title;
this.Name = name;
this.Age = age;
}
}
class Employee {
Int Salary;
private Person person;
public Employee(Person p, Int salary) {
this.person = p;
this.Salary = salary;
}
}
Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);
组合通常 “具有” 或 “使用” 关系。这里 Employee 类有一个 Person。它不会从 Person 继承,而是将 Person 对象传递给它,这就是它“拥有”Person 的原因。
现在假设您要创建一个 Manager 类型,最终得到:
class Manager : Person, Employee {
...
}
这个例子可以正常工作,但是,如果 Person 和 Employee 都声明了Title
? Manager.Title 应该返回 “运营经理” 还是 “先生”?在构图下,这种歧义可以更好地处理:
Class Manager {
public string Title;
public Manager(Person p, Employee e)
{
this.Title = e.Title;
}
}
Manager 对象由 Employee 和 Person 组成。标题行为取自员工。这种明确的组合消除了其他事物的歧义,你会遇到更少的错误。