Oop 与面向对象设计相关的组合是什么?
我听到(并在这个网站上读到)很多关于“重作文轻继承”的文章Oop 与面向对象设计相关的组合是什么?,oop,design-patterns,language-agnostic,composition,Oop,Design Patterns,Language Agnostic,Composition,我听到(并在这个网站上读到)很多关于“重作文轻继承”的文章 但什么是合成?我从人:哺乳动物:动物的角度理解遗传,但我真的看不出堆肥的定义。。有人能告诉我吗?组成就是组成整体的部分。汽车有轮子、发动机和座椅。继承是一种“是”的关系。组合是一种“has a”关系。组合的一个例子是,在另一个类中有一个类的实例,而不是从它继承 佩奇有一篇很好的文章解释了为什么人们说“偏好组合而非继承”,并举例说明了原因。组合指的是将简单类型组合成更复杂的类型。在您的示例中,组合可以是: Animal: Skin
但什么是合成?我从人:哺乳动物:动物的角度理解遗传,但我真的看不出堆肥的定义。。有人能告诉我吗?组成就是组成整体的部分。汽车有轮子、发动机和座椅。继承是一种“是”的关系。组合是一种“has a”关系。组合的一个例子是,在另一个类中有一个类的实例,而不是从它继承
佩奇有一篇很好的文章解释了为什么人们说“偏好组合而非继承”,并举例说明了原因。组合指的是将简单类型组合成更复杂的类型。在您的示例中,组合可以是:
Animal:
Skin animalSkin
Organs animalOrgans
Mammal::Animal:
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person::Mammal:
string firstName
string lastName
如果您想完全使用合成(并摆脱所有继承),它将如下所示:
Animal:
Skin animalSkin
Organs animalOrgans
Mammal:
private Animal _animalRef
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person:
private Mammal _mammalRef
string firstName
string lastName
这种方法的优点是,类型哺乳动物
和人
不必符合其先前父代的界面。这可能是一件好事,因为有时对超类的更改会对子类产生严重影响。
他们仍然可以通过这些类的私有实例访问这些类的属性和行为,如果他们想公开这些以前的超类行为,他们可以简单地将它们封装在公共方法中
我在这里找到了一个很好的例子链接:有三种方法可以为类提供行为。您可以将该行为写入类中;您可以从具有所需行为的类继承;或者可以将具有所需行为的类作为字段或成员变量合并到类中。最后两种形式代表代码重用,最后一种形式——组合——通常是首选。它实际上并没有为类提供所需的行为—您仍然需要在字段上调用该方法—但它对类设计的约束更少,从而更易于测试和调试代码。继承有它的地位,但组合应该是首选
class Engine
{
}
class Automobile
{
}
class Car extends Automobile // car "is a" automobile //inheritance here
{
Engine engine; // car "has a" engine //composition here
}
组合-对象的功能由不同类的集合组成。在实践中,这意味着持有一个指向另一个工作被延迟到的类的指针
继承-对象的功能由其自身的功能加上其父类的功能组成
至于为什么组合比继承更受欢迎,请看一下。组合 简单地说就是使用引用其他对象的实例变量。
为了说明继承如何与代码重用部门中的组成进行比较,请考虑这个非常简单的例子:
1-通过继承进行编码
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple extends Fruit {
}
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
当您运行Example1应用程序时
,它会打印出“剥皮很吸引人”,因为Apple继承(重用)了Fruit对peel()
的实现。但是,如果在将来的某个时候,您希望将peel()
的返回值更改为键入peel,您将中断Example1
的代码。您对水果的更改破坏了Example1的代码,即使Example1直接使用Apple,并且从未明确提到水果。
有关更多信息,请参阅
下面是它的样子:
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
//...
}
class Fruit {
// Return a Peel object that
// results from the peeling activity.
public Peel peel() {
System.out.println("Peeling is appealing.");
return new Peel(1);
}
}
// Apple still compiles and works fine
class Apple extends Fruit {
}
// This old implementation of Example1
// is broken and won't compile.
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
2-通过合成编码
组合为Apple
重用Fruit的实现peel()
提供了一种替代方法。与扩展Fruit
不同,Apple
可以保存对Fruit
实例的引用,并定义自己的peel()
方法,该方法只需调用水果上的peel()
。代码如下:
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
class Example2 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
有关更多信息和聚合是一个。。。关系。聚合可以是简单的组合,或者如果它是类似事物的集合(例如,汽车上的车轮),则可以将其视为集合。一辆汽车可以有四个单独的车轮,它们是唯一标识的,也可以有一组车轮。这取决于使用情况。如果使用一个集合类,那么集合本身就是一个聚合。所以我可以这样说:“组合是当我在类B
中创建类a
的对象时(而不是从类a
中对类B
进行子类化)。”哦。好的,收到了,稍后再回答。是的,我可以这么说。不是一个类[C2]在另一个类[C1]中的实例,而是一个类在另一个类的实例中的实例。前者可能被误解为在定义C1时实例化了C2,这不应该是常见的。