优先使用对象组合,而不是类继承

极限编程》(Extreme programming)的指导原则之一是“只要能用,就作最简单的”。一个彷佛须要继承的设计经常可以戏剧性地使用组合来代替而大简化,从而使其更加灵活。所以,在考虑一个设计时,问问本身:“使用组合是否是更简单?这里真的须要继承吗?它能带来什么好处?”编程

继承和组合的比较:设计

  面向对象系统中功能复用的两种最经常使用技术是类继承和对象组合(object composition)。正如咱们已解释过的,类继承容许你根据其余类的实现来定义一个类的实现。这种经过生成子类的复用一般被称为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,父类的内部细节对子类可见。对象

  对象组合是类继承以外的另外一种复用选择。新的更复杂的功能能够经过组装或组合对象来得到。对象组合要求被组合的对象具备良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),由于对象的内部细节是不可见的。对象只以“黑箱”的形式出现。继承

        继承和组合各有优缺点。类继承是在编译时刻静态定义的,且可直接使用,由于程序设计语言直接支持类继承。类继承能够较方便地改变被复用的实现。当一个子类重定义一些而不是所有操做时,它也能影响它所继承的操做,只要在这些操做中调用了被重定义的操做。接口

        可是类继承也有一些不足之处。首先,由于继承在编译时刻就定义了,因此没法在运行时刻改变从父类继承的实现。更糟的是,父类一般至少定义了部分子类的具体表示。由于继承对子类揭示了其父类的实现细节,因此继承常被认为“破坏了封装性” 。子类中的实现与它的父类有如此紧密的依赖关系,以致于父类实现中的任何变化必然会致使子类发生变化。当你须要复用子类时,实现上的依赖性就会产生一些问题。若是继承下来的实现不适合解决新的问题,则父类必须重写或被其余更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。一个可用的解决方法就是只继承抽象类,由于抽象类一般提供较少的实现。rem

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

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

  这导出了咱们的面向对象设计的第二个原则:优先使用对象组合,而不是类继承。编译

相关文章
相关标签/搜索