设计模式–创建型模式
1.单例模式(Singleton Pattern)
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
结构图:
主要优点:
(1)提供了对唯一实例的受控访问。因为单例类封装了他唯一的实例,所以他可以严格控制客户怎样以及何时访问它。
(2)可以节约系统资源。因为系统内存中只存在一个对象。
(3)允许可变数目的实例。基于单例模式,开发人员可以进行扩展,既节省系统资源,又解决了单例对象共享过多有损性能的问题。
主要缺点:
(1)由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
(2)单例类的职责过重,在一定程度上违背了单一职责原则。
(3)现在很多的面向对象语言(例Java,C#)的运行环境都提供了自动垃圾回收技术,如果实例化的共享对象长时间不被利用,系统会认为他是垃圾,会自动销毁并回收资源,下次利用时又将被重新实例化,这将导致共享的单例对象状态的丢失。
适用场景:
(1)系统只需要一个实例对象。
(2)客户类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
2.工厂方法模式(Factory Method Pattern)
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式让一个类的实例化延迟到其子类。又叫工厂模式、虚拟构造器模式、多态工厂模式。
结构图:
主要优点:
(1)用户只需要关心所需产品对应的工厂,无需关心创建细节。
(2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂自主决定创建何种产品对象而如何创建这个对象的细节则完全封装在具体工厂的内部。 (3)符合开闭原则。系统加入新产品时,无需修改源代码,只需要增加一个具体工厂和一个具体产品就可以了,系统的扩展性非常好。
主要缺点:
(1)在添加新产品时,需要编写新的产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对的增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
(2)因为需要考虑系统的扩展性,引入了抽象层,在客户端代码层均使用抽象层进行定义,增加了系统的抽象性和理解难度,并且在实现时可能需要用到DOM、反射技术等,增加了系统的实现难度。
适用场景:
(1)客户端不知道其需要的对象的类。
(2)抽象工厂类通过其子类来指定创建哪一个对象。(利用了面向对象的多态性和里氏替换原则)
3.抽象工厂模式(Abstract FactoryPattern)
定义:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们的类。又称为Kit模式。
结构图:
主要优点:
(1)抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了在抽象工厂中声明的那些公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
(2)当一个产族的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族的对象。
(3)增加新的产品族很方便,无需修改原来的系统,符合开闭原则。
主要缺点:
(1)存在开闭倾斜的现象,增加一个新的产品等级结构麻烦,需要对原有系统进行大量的修改,甚至需要修改抽象层代码,违背了开闭原则。
适用场景:
(1)一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都很重要,用户无需关心对象的创建过程,将对象的创建和使用解耦。
(2)系统中有多于一个的产品族,而每次只使用其中的某一个。可以通过配置文件等方式来动态的改变产品族。
(3)同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
(4)产品的等级结构稳定。设计完成后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
4.原型模式(Prototype Pattern)
定义:使用原型实例指定创建对象的种类,并且通过克隆这些原型创建新的对象。
结构图:
主要优点:
(1)提高新实例的创建效率。当创建新的对象实例较为复杂时,使用原型模型可以简化创建对象的创建过程。
(2)扩展性好。由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类编程,而将具体原型类写在配置文件中,增加或减少具体原型类对原有系统都没有任何影响。
(3)原型模式提供了简化的创建结构。
(4)可以使用深克隆的方法保存对象的状态。
主要缺点:
(1)需要为每一个类配备一个克隆方法,而且该方法位于类的内部,当对一个已有的类进行改造时,需要修改源代码违背了开闭原则。
(2)在实现深克隆的时候需要编写较为复杂的源代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。
适用场景:
(1)创建新对象时需要花费很长的时间,占用太多的CPU资源等。
(2)如果系统需要保存对象的状态,而对象的变化状态很小,或者对象本身占用的内存较小时,可以使用原型模式配合备忘录模式。
(3)需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或者很少的几个组合状态,通过复制原型对象得到新的实例可能比使用构造函数来创建新的实例更加方便。
5.建造者模式(Builder Pattern)
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构图:
主要优点:
(1)在建造者模式中,客户端不必知道产品内部的组成细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
(2)每一个具体建造者都相对独立,而与其他具体建造者无关,因此可以很方便的增加或者替换建造者。由于指挥者类针对抽象建造者编程,增加新的具体建造者不必修改源代码,符合开闭原则。
(3)可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也方便使用程序来控制创建过程。
主要缺点:
(1)建造者模式创建的对象一般都具有较多的共同点,其组成部分相似,如果产品之间的差异很大,就不适合使用建造者模式,因此它的使用范围受限。
(2)如果产品内部的结构复杂多变,可能会需要定义很多的具体建造者类来实现这种变化,这就导致系统变得很庞大,增加系统的理解难度和运行成本。
适用场景:
(1)需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量。
(2)需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3)对象的创建过程独立于创建该对象的类。在建造者模式中通过引入指挥者类,将创建过程封装在指挥者类里,而不在建造者类和客户类中。
(4)隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。