委托与继承

 

委托比继承灵活,可以动态配置,不会造成子类级数增长,另外可以通过对象的合成来实现多种功能(Decorator)

继承则相对不灵活,一旦选择了子类后,不能动态配置

委托是黑盒重用(看不到父类方法),继承是白盒重用,应该多使用委托少用继承

继承打破封装。因为子类的实现与父类的实现关系密切,所以父类实现的任何改变将引起子类的变化。

 

让重用机制发挥作用

 

多数人能够理解对象、接口、类、继承等概念。然而,真正的挑战在于应用这些概念来构建灵活、可重用的软件。设计模式告诉你如何做到这一点。

 

继承VS合成

 

在面向对象系统的功能重用过程中,两个最普遍的技术就是类的继承和对象合成。我们之前解释过,类的继承让你能通过某个类的实现定义另外的类的实现。通过子类实现的重用通常指“白盒重用”。术语“白盒”指的是可见性:通过继承,父类的内部结构对子类来说是可见的。

对象合成是类继承的替代选择。通过汇编或合成对象可以获得新的功能。对象合成需要用来进行合成的对象具备良好定义的接口。这种类型的重用被称为“黑盒重用”,因为对象的内部细节是不可见的。

 

继承和合成都有各自的优缺点。类的继承是在编译时静态定义的,且由于语言的直接支持,可直接实现。类继承也使得可以较易的在重用时修改实现,当子类重载部分而不是所有的操作时,它同样可影响其继承而来的操作(在使用了重载的情况下)。

类继承也有一些缺点。首先,由于继承在编译时完成,因此,不可能在运行时改变继承自其父类的实现;其次,更糟的是,父类通常定义了其子类的部分物理表示。因为继承向子类暴露了父类的实现细节,故有这样的说法继承打破封装。因为子类的实现与父类的实现关系密切,所以父类实现的任何改变将引起子类的变化。

当你试图重用一个子类时,这种实现依赖可能会产生问题,由于通过继承得到的实现不可能在每个方面都适合新的问题领域,故父类可能会要更改或重写。这种依赖限制了灵活性,并最终限制了可重用性。解决的方案是仅仅通过抽象类来继承,因为抽象类通常提供很少的实现、甚至根本没有任何实现。

 

对象合成是对象通过获得其他对象的引用,而在运行时动态完成的。合成需要对象表明各自的接口,这需要小心的设计接口,以利对象可与其他更多对象一起使用。因为对象通过其接口进行访问,我们不必打破封装。只要拥有同一类型,任何对象都能在运行时替换为另外的对象。而且,因为对象的实现是根据其接口而编写,这将减少实现依赖。

对象合成在系统设计中还有另外一个效果。任用对象合成能帮助你保持类的封装而可专心处理一项任务。你的类和类层次将保持较小,很少出现变成难以管理的层次大怪。另一方面,基于对象合成的设计中将拥有更多的对象(在更少的类的情况下),系统的行为将决定于它们之间的相互关系,而不是在一个类中定义。

这里导出了我们的第二个面向对象设计原则:

 

优先采用对象合成来代替类继承

 

理想情况下,你应该在不必编写新组件的情况下达成重用,你应当可以通过对象合成来组装存在的组件而得到所需的功能。但这种情况很少,因为在实践中可获得的组件集并不十分丰富。

根据我们的经验,设计中采用继承作为重用技术的情况有些过滥,其实,在设计中更多的任用对象合成技术将带来更好的可重用性。在设计模式中,你将看到一次又一次的对象合成应用。

 

委托

 

委托是使得合成技术在重用中完成和继承一样功能的一个办法。在委托中,当处理请求时,涉及到两个对象:接收者对象委托其操作给委托人对象(代表)。一个类比是子类处理发给父类的请求。但是,在继承中,继承而来的操作总可以通过this成员变量指向接收者对象;而在委托中,为了达成同样的效果,接收者将自己传递给委托人,以让被委托的操作指向接受者。

例如,代替将窗口类作为矩形类的子类的方案,窗口类可以通过保持一个矩形实例变量,并将矩形的详细行为委托给它,而重用矩形类的行为。换句话说,“窗口是矩形”的替代方案是,“窗口可以作为一个矩形”。应用委托,窗口对象可以明确的发送请求给其矩形对象实例;而如果不采用委托,它可能必须继承这些操作。

 

委托的主要优点在于,可以容易的在运行时合成(compose)行为并改变其合成方式。假设矩形类和圆类拥有同样的类型,我们的窗口可以在运行时变成圆,只需通过用圆实例替换矩形实例。

 

委托与其它通过对象合成来增强软件灵活性的技术一样,都有一个共同的缺点:动态、高参数化的软件与相对静态的软件相比,比较难以理解。另外,委托也存在运行时效率问题。只有当运用委托的简化性超过其复杂性的情况下,委托才是一种好的设计选择。很难说明何时运用委托,因为其效率取决于其应用环境,而对效率的判断取决于设计者运用它的经验。最好的应用委托的情况是当它运用于高度程式化的环境----即,在标准模式中。

 

有几个设计模式应用了委托,如状态模式、策略模式、和访问者模式。在状态模式中,一个对象委托其请求给状态对象,状态对象表示了它的当前状态;策略模式中,一个对象委托一个详细请求给另外一个表示携带请求的策略的对象;一个对象只有一个状态,但可以有多个针对不同请求的策略,这两个模式的目的都是为了通过改变委托请求的对象,而改变对象的行为。在访问者模式中,对对象结构的每一个元素的执行操作总是委托给了访问者对象。

在其他的模式中委托的应用,没有在上述模式中那么重要。解调器模式用一个对象去协调其它对象的通信,解调器对象有时简单的直接用其它对象执行操作,有的时候,它提交一个对自身的引用,此时真正运用了委托;责任链对象通过将请求沿着对象链从一个对象传到另外一个,从而处理请求。有时,请求携带了一个接收请求的原始对象的引用,此时,该模式运用了委托;桥接模式分离了实现与其抽象,当抽象和特定实现匹配时,抽象可简单的委托对具体实现的操作。

 

委托是对象合成的一个特例。这说明,为了代码重用,总能用对象合成机制来替换继承。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值