理解组合对象与类继承

Posted DDDDemo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解组合对象与类继承相关的知识,希望对你有一定的参考价值。

  

1.概念解析

  • 继承:"继承"是面向对象编程中的一个概念。

    面向对象编程的单一职责原理(SPR-Single Responsibility Principle)规定对象只能有一个职责。就一个类而言,应该仅有一个引起它变化的原因。 为什么要把不同的职责分配到不同的类中呢?因为每一个职责都是变化的一个轴线,当需求变化时,该变化会反映为类的职责的变化。如果一个类承担了多于一个的职责,那么就意味着引起它的变化的原因会有多个。如果一个类承担的职责过多,那么就等同于把这些职责耦合在了一起。一个职责的变化可能会抑制到该类完成其他职责的能力,这样的耦合会导致脆弱的设计。当变化发生时,设计会受到意想不到的破坏。

    这个原则的核心含意是:一个类应该有且仅有一个职责。关于职责的含意,面向对象大师Robert.C.Martin有一个著名的定义:所谓一个类的职责是指引起该类变化的原因,如果一个类具有一个以上的职责,那么就会有多个不同的原因引起该类变化,其实就是耦合了多个互不相关的职责,就会降低这个类的内聚性

    例如我们现在有两个类,D和C。那么类D的对象可以使用仅对类C对象有效的方法或属性,它使得这些方法和属性就像是由D定义的。这时,C是D的父类,D是C的子类。由于在继承过程中,父类的内部细节对子类完全可见,因此通过继承的代码复用被称为“白盒式代码复用”(white-box reuse)。

    因此,当你通过从另一个对象继承的方式来创建一个新的对象时,目标就应该是使得新的对象有一个相对于原始对象更加特定的版本。

  • 对象组合(组合对象):将多个元素作为一个对象来处理,需要将它们组合。

    一个对象可以把对象作为自己的成员变量,如果用这样的类创建对象,那么该对象中就会有其它对象,也就是说该对象将其他对象作为自己的组成部分(这就是人们常说的Has-A),或者说该对象是由几个对象组合而成。

    对象组合就是通过对现有的对象进行拼装(组合)产生新的、更复杂的功能,而由于对象之间各自内部细节不对外可见,所以这种方式的代码复用被称为“黑盒式代码复用”(black-box reuse)。对象组合要求被组合的对象具有良好定义的接口。

  举例:

<?php

class person{

  public $name;

  public $gender;

  public function say(){

    echo $this->name," \tis ",$this->gender,"\r\n";

  }

}

class family{

  public $people;

  public $location;

  public function construct($p,$loc){

    $this->people=$p;

    $this->location=$loc;

  }

}

$student=new person();

$student->name=\'Tom\';

$student->gender=\'male\';

$student->say();

$tom=new family($student,\'peking\');

 

  以上代码中,定义了两个类,一个是person,一个是family;在family类中创建person类中的对象,把这个对象视为family类的一个属性,并调用它的方法处理问题,这种复用方式就叫“组合”。

 

2、继承与组合区别

  类继承是在编译时刻静态定义的,且可直接使用,因为程序设计语言直接支持类继承。类继承可以较方便地改变被复用的实现。当一个子类重定义一些而不是全部操作时,它也能影响它所继承的操作,只要在这些操作中调用了被重定义的操作。
  但是类继承也有一些不足之处。首先,因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。更糟的是,父类通常至少定义了部分子类的具体表示。因为继承对子类揭示了其父类的实现细节,所以继承常被认为“破坏了封装性” 。子类中的实现与它的父类有如此紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,实现上的依赖性就会产生一些问题。如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。一个可用的解决方法就是只继承抽象类,因为抽象类通常提供较少的实现。

 对象组合是通过获得对其他对象的引用而在运行时刻动态定义的。组合要求对象遵守彼此的接口约定,进而要求更仔细地定义接口,而这些接口并不妨碍你将一个对象和其他对象一起使用。这还会产生良好的结果:因为对象只能通过接口访问,所以我们并不破坏封装性;只要类型一致,运行时刻还可以用一个对象来替代另一个对象;更进一步,因为对象的实现是基于接口写的,所以实现上存在较少的依赖关系

  对象组合对系统设计还有另一个作用,即优先使用对象组合有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。另一方面,基于对象组合的设计会有更多的对象 (而有较少的类),且系统的行为将依赖于对象间的关系而不是被定义在某个类中
  这导出了我们的面向对象设计的第二个原则:优先使用对象组合,而不是类继承

 

推荐阅读》》

面向对象编程中的继承和组合的简单比较

面向对象的编程概念:组合(Composition)和聚合(aggregation)

以上是关于理解组合对象与类继承的主要内容,如果未能解决你的问题,请参考以下文章

组合与封装

Java 继承多态与类的复用

类的组合与封装

java中类与类之间的关系讲解

python3 类 组合

Java的继承与组合