【建造者模式 Builder】
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
解释
指挥者(Director):根据小人的需求构建小人对象。在指导中不涉及产品的创建,只负责保证复杂对象各部分被创建或按某种顺序创建。
Builder:是为创建一个Product对象的各个部件指定的抽象接口,类中需要声明一个得到产品建造后结果的方法GetResult。
具体的建造者(ConcreteBuilder):具体实现如何画小人的头 手 脚的各个部分,返回一个建造好的产品。
具体的产品(Product):它要包含那些定义组件的类,包括将这些组件装配成产品的接口。
例子
客户端:顾客,想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
产品角色:最后的套餐,所有的东西放在同一个盘子里面。
优点
1.使用建造者模式可以使客户端不必知道产品内部组成的细节。
2.具体的建造者类之间是相互独立的,对系统的扩展非常有利。
3.由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
场合
1.用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常是复杂的变化的。
2.当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
3.当构造过程必须允许被构造的对象有不同的表示时。
特点
一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
原因
例如:一个打印机需要打印的内容可能有很多,但是正在打印的只有一个。但是如何保证一个类只有一个实例并且这个实例易于被访问呢?
这就需要定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象,让类自身负责保存它的唯一实例,这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。
代码
打印机类名为Printer,类中包含大量的成员方法:构造函数Printer(),打印A纸方法PaperA()、PaperB()
class Printer { public Printer;{} //初始化 public void PrinterA() {} //打印纸张A public void PrinterB() {} //打印纸张B }
1.由于每次使用new关键字来实例化Printer类时都将产生一个新对象,为了确保Printer实例的唯一性,我们需要禁止类的外部直接使用new来创建对象,因此需要将Printer的构造函数的可见性改为private。
class Printer { private Printer;{} //初始化 public void PrinterA() {} //打印纸张A public void PrinterB() {} //打印纸张B }
private static Printer tm = null;
public static Printer GetInstance() //此方法是获得本实例的唯一全局访问点 { if (tm == null) //如果实例不存在,则new、一个新的实例,否则返回已有的实例 { tm = new TaskManager(); } return tm; }
优点
1.保证唯一的实例,单例模式因为Singleton类封装它的唯一实例,这样它就可以严格控制客户端怎样访问它以及何时访问它,简单的说就是对唯一实例的受控访问。
2.由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3.灵活性,因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点
1.开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
2. 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
3.对象生存期:不能解决删除单个对象的问题,只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。
4.违背了单一职责原则,因为类的负担过多。
场合
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如资源管理器。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
3.客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。