设计模式| 创建型模式

时间:2022-06-10
本文章向大家介绍设计模式| 创建型模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言

GOF23种设计模式中创建型模式共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
 工厂模式中有三种形态:Simple Factory简单工厂模式、Factory Method工厂方法模式、Abstract Factory抽象工厂模式。

其他同系列的文章还有: 面向对象编程中的六大原则 设计模式| 创建型模式 设计模式| 结构型模式 设计模式| 行为型模式 (上) 设计模式| 行为型模式 (下) 欢迎阅读,评论!!!

工厂模式的主要实现原理是:

1.抽象(接口或者抽象类)出公共的产品,抽象出公共的工厂,
2.具体的产品是公共产品的实现或者子类,具体的工厂是公共工厂的实现或者子类。
3.因为公共的产品、公共的工厂的存在,使得不同的具体产品在对外可以返回相同的产品,不同的工厂都可以调用相同的方法。
4.相当于工厂(不同的工厂)出来的产品都是相同的壳子,都有相同的方法,
  但是壳子里面具体是什么产品和方法执行后的结果是什么取决于真正产品的类实现。
5.具体产出什么产品由参数、特定的具体工厂的初始化以及方法的调用,无法实现自动化创建产品,
  主要的目的是为了代码的好维护和扩展。

工厂模式的主要使用场景:

作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
有一点需要注意的地方就是复杂对象适合使用工厂模式,
而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。
如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。
假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。

再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。
也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。

0、简单工厂模式

简单工厂(又被称为静态工厂)模式是最简单的工厂模式主要用于生产同一等级结构中的任意产品或者方案,
简单工厂模式涉及抽象产品(Product)角色及具体产品(Concrete Product)角色、工厂角色(Factory )等三个角色。

实现的过程是这样:抽象出一个抽象产品,实现抽象产品后形成很多具体产品类,
               一个工厂类中方法中,根据不同的参数,定向生产出特定的具体产品。
               但增加新的产品,就要修改原工厂类,符合单一职责原则,不符合开放-封闭原则。

1、工厂方法模式

1.通俗来说就是一个产品的生产过程,分解到了两个抽象过程,一个是自身产品的抽象,一个是生产出这个产品的工厂抽象,
2.所以实际的生产流程中,有多少种产品就会有有多少个对应的工厂一一对应,达到特定工厂生产特定产品。
3.在后续添加新产品的时候,实现一个对应的新工厂即可,扩展性非常的好。
4.根据需要,实现特定的工厂即可。

工厂方法模式和简单工厂的区别:工厂方法模式只是把简单工厂中的工厂实体类化为两层:抽象工厂类和实际产品的工厂实体类,
更利于扩展。

2、抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,
但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。
此时,我们可以考虑将一些相关的产品组成一个“产品族”,
由同一个工厂来统一生产,这就是我们本文将要学习的抽象工厂模式的基本思想。

因为比较抽象,下面举个例子:
抽象产品:car、suv
具体产品:高端car、高端suv
        中端car、中端suv
        低端car、低端suv   
抽象工厂:工厂 (生产car、生产suv)
具体工厂:高端工厂(生产高端car、高端suv)
        中端工厂(生产中端car、中端suv)
        低端工厂(生产低端car、低端suv)
高端car、高端suv 就算一个产品族 

以上就是抽象工厂模式:实现一个具体工厂生产出多个具体产品的效果。

3、单例模式

定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

为什么使用单例模式

需要确保某个类只要一个对象,
或创建一个类需要消耗的资源过多,如访问IO和数据库操作等,这时就需要考虑使用单例模式了。

4、建造者模式

复杂对象的组装与创建-建造者模式

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
     这个概念看起来总是这么深奥难懂。大概的意思,同一套构建流程,但是基于不同的构建流程细节,创建出了不同的产品(表示)。

建造者模式属于创建型模式。顾名思义,builder 的意思是建造者或者建筑工人。
例如,楼房都是千差万别,楼房的外形,层数,内部房间的数量,房间的装饰都不一样。但是建筑一座楼房,抽象出来的建筑流程是确定的
都可以归纳为几个步骤:打桩、建地基、搭框架、内部建设等。同理,建造者设计模式也是基于这样的概念而生的,
这个设计模式用来解决什么样的情况呢:面对 "一个复杂对象" 的创建,其流程不变,但每个流程实现的具体细节是会变化的。

四个要素:

产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。
       在本类图中,产品类是一个具体的类,而非抽象类。实际编程中,
       产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。
抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。
          一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回产品。
建造者:实现抽象类的所有未实现的方法,不同的子建造者提供了不同的流程细节。
       具体来说一般是两项任务:组建产品;返回组建好的产品。
导演类:负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。
       一般来说,导演类被用来封装程序中易变的部分。

A.建造者模式的优点

首先,建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,
一般产品类和建造者类是比较稳定的,
因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。

 其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,
 基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。

B.建造者模式与工厂模式的区别

我们可以看到,建造者模式与工厂模式是极为相似的,总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。
在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。

与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,
因此将对象的创建过程独立出来组成一个新的类——导演类。

也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品; 而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。 由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。

C.总结

建造者模式与工厂模式类似,他们都是建造者模式,适用的场景也很相似。

一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式。

5、原型模式

对象的克隆-原型模式

原型模式是非常简单的一种设计模式, 在多数情况下可被理解为一种深复制的行为。

在Objective-C中使用原型模式, 首先要遵循NSCoping协议(OC中一些内置类遵循该协议, 
例如NSArray, NSMutableArray等)。刚才我们提到了深复制, 一图以蔽之:
深复制就是开辟新内存实现真正的内存复制, 浅复制, 只复制指针, 堆内存不变. 在我们设计系统时,
有时一些对象需要根据用户操作完成拷贝备份等操作, 这时候, 如果再去按照原来的方法初始化一遍对象就会带来一些不便和问题:

1.该对象的某些属性是在用户操作过程中产生的,不能够仅凭一个 initXXX 方法赋值; 2. 常规赋值太过麻烦复杂, 而且破坏封装.

常见的使用场景: 1. 结构复杂的类型, 例如《编程之道》中提及的Mark类型; 或者是相似类, 结构一致, 但是属性不同. 2.不管是什么对象,只要复制自身比手工实例化要好,都可以是原型对象。

好处:

1.使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,
  它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
2.使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
3.在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,
  假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

参考文章: https://blog.csdn.net/crazymo_/article/details/72848566