Builder生成器模式与Composite组合模式

一.Builder生成器模式

Builder模式的缘起

假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化。

如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正……

动机(Motivation)

在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?

意图(Intent)

将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示

——《设计模式》GoF

结构(Structure)

image

协作(Collaborations)

image

游戏框架中的Builder应用

系统接口部分Builder

image

Builder不需要关心具体的门是什么样子的,墙是什么样子的,它只是定义了轴线的东西。

系统相对稳定的部分Director

image

系统相对变化的部分ConcreteBuilder

image

Client

image

Director和抽象类Builder是绑定的比较紧的,但是在它里面,没有任何具体ConcreteBuilder的任何信息。也就是说,Director不会被具体依赖所改变,当ConcreteBuilder改变时,Director不用变。

另外,客户端需要new一个ConcreteBuilder,当ConcreteBuilder改变时,这个程序还是需要改变Client。这里我们可以用一种动态的机制回避这种改变。我们可以从一个配置文件里面读取ConcreteBuilder具体类的名字,和程序集的名字,然后通过动态反射,让客户程序不发生任何依赖的改变。

image

这样,当ConcreteBuilder需要改变的时候,只需要新增一个Builder的子类,修改一下配置文件就可以了。

这是非常符合开放封闭原则的,对扩展开放,对更改关闭。

这也符合依赖倒置原则。房屋的构建过程是一个高层抽象,房屋的具体实现细节依赖于高层抽象。高层抽象比较稳定,底层实现细节比较多变。

Builder模式的几个要点

Builder模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法(即Director,如上面例子中的GameManager),而复杂对象的各个部分(即ConcreteBuilder)则经常变化。

变化点在哪里,封装哪里——Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。(例如房屋构造如果经常改变,那么这个Builder模式也没有意义了)

AbstractFactory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。Builder模式通常和Composite模式组合使用。

.NET框架中的Builder应用

在ASP.Net中,我们在写一个Page类时,这个类继承自System.Web.UI.Page。Page其实就是一个Builder,它是一个容器。它有很多方法,就是所谓的BuilderPart()方法,例如:OnInit()、OnLoad()、OnPreRender()、Render()等,它们都是虚方法,我们都可以去重写,提供我们自己的实现。当我们编译到bin文件夹下的dll时,我们就生成了一个我们自己的ConcreteBuilder实例。实际上系统使用的是Page基类。

转自:http://blog.csdn.net/xingxing513234072/article/details/9222595

二.Composite组合模式

1.1.1 摘要

      在软件系统设计中,我们经常会遇到整体和部分的设计问题,例如为一家架构完善的公司设计系统时,我们在系统设计过程中应该更加注重这种整体和部分的关系(总部和分部的关系),这就是我们今天要介绍的组合模式(Composite)。

      组合模式(Composite)把对象构造成为一棵对象树,现在让我们简短回忆一下树的定义。

      树是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

      每个结点有零个或多个子结点;

      每一个子结点只有一个父结点;

      没有前驱的结点为根结点;

      除了根结点外,每个子结点可以分为m个不相交的子树(参考维基百科);

      使用频率: clip_image001  medium high

  • 定义

        组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次关系(树状结构)。组合模式使得用户对单个对象和组合对象使用具有一致性。

  • 意图

        希望用户可以忽略单个对象和组合对象的区别,统一使用组合结构中的所有对象(封装变化的思想)。

  • 结构图

composite0

图1组合模式(Composite)结构图

  • 参与者

        Component

        它是一个抽象角色,为对象的组合提供统一的接口。

        为其派生类提供默认的行为。

        通过该接口来访问和管理Child Components(节点后继)。

        通过该接口来访问Parent Components(节点前驱)。

        Leaf

        代表参加组合的叶子对象(叶子没有后继)。

        定义组成原始对象的行为。

        Composite

        定义非叶子对象的行为。

        实现Component中的孩子操作行为(如:Add(),Remove() 等)。

1.1.2 正文

      在我们学习组合模式(Composite)之前,让我们先讲解一下透明方式和安全方式。

      透明方式:在Component中声明所有用来管理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。

      大家可以回忆一下代理模式(Proxy)中,Proxy,RealSubject类和Subject接口具备一致的行为接口,从而使得被代理者对于客户端是透明的。

      正由于我们的Composite和Leaf都具备一致的接口行为,但我们知道Leaf不应该具有Add(),Remove()及GetChild()方法,因为我们叶子节点不能再添加和移除节点了。

      安全模式:在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。

 

composite1

图2透明方式的组合模式(Composite)结构图

 

 composite2

图3安全方式的组合模式(Composite)结构图

 

      通过前面的介绍我们知道透明和安全方式组合模式(Composite)的区别在于是否在抽象接口Component中定义子对象的管理行为。

组合模式(Composite)和装饰者模式(Decorator)的关系

 decorator

图5 Decorator中的Composite

 

      通过上图我们可以发现,装饰者模式(Decorator)是通过组合模式(Composite)来构建起一棵对象树,然后通过装饰者的子类来扩展装饰者(即Composite)的行为,从而实现对具体组件装饰行为(即Leaf)。

 

1.1.3 总结

      1.组合模式(Composite)采用树形层次结构来实现对象容器,如:绘图程序例子我们把各种各样的图形添加的Shape中,从而构造起一条对象链,把“一对多”的关系转化“一对一”的层次关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。

     2.组合模式(Composite)中,透明方式和安全方式的使用抉择,虽然透明方式有可能违背面向对象的SRP原则(单一职责),而安全方式没有很好的封装变化,但在实际开发时我们要根据具体的情况权衡利弊。

转自:http://blog.csdn.net/yingchunhua365/article/details/15808749
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值