[设计模式]让面向对象编程更加灵活的模式 联系客服

发布时间 : 星期一 文章[设计模式]让面向对象编程更加灵活的模式更新完毕开始阅读41e86d2ded630b1c59eeb501

Charpter 10让面向对象编程更加灵活的模式

composition provides greater flexibility than inheritance

本章内容包括:组合(Composite)模式,装饰(Decorator)模式and外观(Facade)模式。

10.2组合模式

组合模式为树型结构,随着引入的规则会变得越来越难以维护,组合模式不能很好地在关系数据库中保存数据,但却非常适合用于XML持久化。 适用:

1、用于对象的部分-整体层次结构,如树形菜单、文件夹菜单、部门组织架构图等; 2、对用户隐藏组合对象与单个对象的不同,使得用户统一地使用组合结构中的所有对象。

Composite比较容易理解,想到Composite就应该想到树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。 Composite好处:

1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。

2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。

结构分为3部分,分别为通用的Component(部件),Leaf(叶子)和Composite(组合),组合充当节点,节点可以添加其子节点或叶子,叶子不能再添加任何东西,这样就构成一个树型的结构。

如Army(军队)和Unit(单位),Army可以与Army合并,也可以添加单个Unit,而Unit

作为最基本的局部对象不能再进行添加操作。

下面以图像的绘制为例:

这样引入Composite模式后,客户端程序不再依赖于复合图像元素的内部实现了。然而,我们程序中仍然存在着问题,因为Line,Rectangle,Circle已经没有了子对象,它是一个基本图像元素,因此Add(),Remove()的方法对于它来说没有任何意义,而且把这种错误不会在编译的时候报错,把错误放在了运行期,我们希望能够捕获到这类错误,于是在add和remove函数中抛出异常。

这样改进以后,我们可以捕获可能出现的错误,做进一步的处理。上面的这种实现方法属于透明式的Composite模式,如果我们想要更安全的一种做法,就需要把管理子对象的方法声明在树枝构件Picture类里面,这样如果叶子节点Line,Rectangle,Circle使用这些方法时,在编译期就会出错,看一下类结构图:

这种方式属于安全式的Composite模式,在这种方式下,虽然避免了前面所讨论的错误,但是它也使得叶子节点和树枝构件具有不一样的接口。这种方式和透明式的Composite各有优劣,具体使用哪一个,需要根据问题的实际情况而定。

10.3装饰模式

组合模式帮助我们聚合组件,而装饰模式则使用类似结构来帮助我们改变具体组件的功能。 问题结构分析:

可以看出,这样的机构不够灵活,当你想要创建一个既有钻石但同时存在污染的Plains时,显然不可能再创建一个Diamon-PollutedPlains类。 让我们来看看通过装饰模式怎么做到这一点:

Plains仅仅作为被装饰的对象,在继承于Tile的时候添加了一个私有属性wealthFactor。TileDecorator以Plains为核心,不断地通过__construct添加装饰类以达到创建复杂地形的效果。

abstract class Tile{

abstract function getWealthFactor(); }

class Plains extends Tile{

}

abstract class Decorator extends Tile{ protected $tile;

function __construct(Tile $tile){ $this->tile=$tile; } }

class DiamondDecorator extends Decorator{ function getWealthFactor(){

return $this->tile->getWealthFactor()+2; } }

class PollutedDecorator extends Decorator{ function getWealthFactor(){

return $this->tile->getWealthFactor()-4; } }

$pdplains=new PollutedDecorator(new DiamondDecorator(new DiamondDecorator(new Plains()))); echo $pdplains->getWealthFactor(); ?>

private $wealthFactor=2; function getWealthFactor(){ return $this->wealthFactor; }

10.4外观模式

Facade模式解说:

外观模式是一个十分简单的概念,它只是为一个分层或一个子系统创建一个单一的入口。 我们平时的开发中其实已经不知不觉的在用Facade模式,现在来考虑这样一个抵押系统,当有一个客户来时,有如下几件事情需要确认:到银行子系统查询他是否有足够多的存款,到信用子系统查询他是否有良好的信用,到贷款子系统查询他有无贷款劣迹。只有这三个子系统都通过时才可进行抵押。我们先不考虑Facade模式,那么客户程序就要直接访问这些子系统,分别进行判断。类结构图下:

可以看到,在不用Facade模式的情况下,客户程序与三个子系统都发生了耦合,这种耦合使得客户程序依赖于子系统,当子系统变化时,客户程序也将面临很多变化的挑战。一个合情合理的设计就是为这些子系统创建一个统一的接口,这个接口简化了客户程序的判断操作。看一下引入Facade模式后的类结构图:

可以看到引入Facade模式后,客户程序只与Mortgage发生依赖,也就是Mortgage屏蔽了子系统之间的复杂的操作,达到了解耦内部子系统与客户程序之间的依赖。

最后贴一个来自维基的解说图: