设计模式深入浅出(二)对象创建——Builder,原型,单例

来源:互联网 发布:windows hadoop2.6 编辑:程序博客网 时间:2024/06/06 12:49

Builder

Builder模式,顾名思义,建造者。

这个模式让我想到了前一段时间的装修。现在的装修工程一般是这样配置的:有一个项目经理,全权由他负责及调度手下的泥工,电工,木工,油漆工的工作。整个装修阶段,泥工,电工等工种会轮流(反复)进场或中间有些交叉,比如,房间铺设电线,需要电工在墙上,地上先开槽,再铺线,当电工做完电线铺设后,需要将开槽回填,这时候需要泥工进场。而当泥工铺好瓷砖等之后,又需要电工重新进场安装开关,照明等。

而这一切的工种调度及施工,则有项目经理安排,作为业主的我,只需要与项目经理沟通。也就是整个装修工程,对我而言有了统一的接口(项目经理),我不需要关心具体到底是泥工,电工还是油漆工在施工(当然,如果现实中肯定不能这样,不然装修到最后你撞墙也晚了:( )。

恩,到这里我们进行一下抽象。项目经理,负责工作的协调,我们抽象为Director(导演)。泥工,电工,木工,油漆工,我们将他们分配到一个施工队,叫Builder。Builder向外暴露一系列接口,用来生产产品的某一步骤(或阶段产品),如NiGong(泥工),DianGong(电工)。

这样,整个装修工程就抽象为:项目经理(Director)指导调度他的施工队(Builder)的不同工种(Builder的不同接口),最终生产一个装修好的房子(Product)。 UML图如下所示:
这里写图片描述

OK,让我们再想一下,现在的装修风格各种各样:有地中海,美式,北欧,中式等等。那我们假设一个施工队只能会一种装修风格,那就需要美式施工队,中式施工队等。为了满足业主的不同风格要求,项目经理手下有多种施工队,在每次装修工程中,项目经理会根据业主的选择,调动相应的施工队进行施工。UML图为:
这里写图片描述

这里我们对builder通过继承(或协议)进行了扩展,使其支持多种不同的装修风格。而在Director的装修方法中,为了能够灵活改变builder,我们添加了一个builder类型参数,用来接收实际执行build操作的builder。

这里我们看到,尽管目前支持了各种装修风格,但是对于业主来说,他还是只需调用Director的装修方法,并将自己需要的builder作为参数传入。而在项目经理这里,他的工种调度流程及方式是不用改的(先有电工开槽做电线,再由泥工回填,做瓷砖,再有木工进场做家具……),因为不管传入的是何种builder,在项目经理这,都是按照其父类builder进行处理的。

好了,这就是builder模式。总结一下,该模式需要两个参与者:Director和Builder。Director负责调度Builder, 而Builder进行具体的build操作。当需要更改最终产品类型时,只需要更换Builder即可。这里说一下,最终的产品,不需要有共同的父类Product,因为不同Builder最终生产出的产品,可能没有任何的共性
Builder模式UML:
这里写图片描述

下面是《设计模式》一书中,Builder模式调用的时序图。
《TUTUTUTT》

可以看到,这里面Client是直接向Builder要结果的(GetResult)。和我们的例子不太一样。这样做的好处是,Director的职责更为单一,只是负责协调。另外一个重要的原因是,Builder模式的最终产品,可能不能够抽象为统一的父类,也就是说Director不能够提供统一的接口来返回产品,因此,Client直接向Builder索要结果。

Builder模式的主要效果:

  1. 将生产过程与实现分离,让我们更灵活更换实现,来获得不同的产品。
  2. 由于有了Director调度,使生产过程更为精细和可控。
  3. 封装了生产流程与生产实践,使用户只关心最终产品,而对产品的生产过程无需关心。

原型

原型模式没什么好说的,在OC中,就是我们常用的NSObject copy。

那么我们为什么使用原型模式呢?个人感觉是使得两个对象间彻底的解耦。

copy的对象与被copy的对象间是一种镜像关系,他们两者只在copy的瞬间有联系,当copy后,两者之间的改动互不影响。这里 涉及到浅拷贝与深拷贝的问题,就不再展开描述。

说一下我们平常编程中的例子:

对于有mutable类型的变量来说,当我们把他们声明为property的时候,应当用copy,这样当该属性被赋值时,会自动拷贝一份。如:

@interface NXStudent : NSObject@property(nonatomic, copy) NSString *name;@end

这是为什么呢?

因为当我们对NXStudent对象的name赋值时,可能赋值的是个NSString 类型,但也可能是NSMutableString类型。当是NSMutableString类型时,那么当在NXStduent对象外部更改string值时,NXStudent对象的name也会一起被改变。这显然与属性的定义相违背。

而copy后,NXStudent的name与外部传入的stirng彻底解耦,无论外部再如何更改,copy 过来的name均不会被影响。

单例

单例的实现方法太多了,在OC中的标准实现,我也不需要写了吧(dispatch_once)?大家应该倒着写都能够写出来。

这里只提一个关键词:单例模式的线程安全。不了解的可以自行百度。

在Cocoa Touch框架中,单例模式也是比比皆是,如UIApplication,就是一个典型的单例。

个人感觉单例模式的应用应该克制,除非是明确的表明,当前程序中需要这么一个全局的唯一对象,否则不应该考虑单例。因为单例模式虽然简单,但是若要用得好,还是要仔细一些。

这主要是考虑到

  1. 单例对象的释放时机。单例对象何时释放?由于他是全局唯一的,因此单例的生命周期往往是和程序一样长的,如果单例持有的资源特别重的话,要考虑好资源释放的问题。
  2. 单例的中间状态。由于单例是全局性的,在执行某些单例方法时,他可能会产生些中间状态,那么这些中间状态是否应该在再次执行单例方法时重置?
  3. 单例的线程安全。
阅读全文
0 0
原创粉丝点击