设计模式之构造型模式
构造型模式包括了:生成器模式、工厂模式、抽象工厂模式、原型模式和备忘录模式。
1、生成器模式(Builder Pattern)
也叫建造者模式。使用多个简单的对象一步一步构建成一个复杂的对象。将一个复杂对象的构建与它的表示分离,使得同样的构建过程(组装过程)可以创建不同的表示(最终构成的对象)。
优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。
举个栗子:生产车间里的工人就是建造者,而生产同一类(构成相同的)产品,比如说电脑,家庭电脑的主要构成 基本上是一致的,主板、CPU、电源、硬盘和鼠标键盘等,但不同的配置,电脑的性能是不一样的。生产车间里就分两个部门的人,生成不同配置的电脑。
第一步:创建指挥者,主管哪个部门或者哪个人生产哪个配置的产品
第二步:创建要生产的产品类
第三步:创建抽象生产者类
第四步:创建生产者实体类
最后:指挥生产
输出:
2、工厂模式(Factory Pattern)
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。在工厂模式中,在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
举个栗子:一个污污的例子,假如有人需要XXOO机器人,他就new一个C罩杯的出来,当然用腻了之后,他想要个D罩杯的,他又要new一个出来。这太麻烦了。如果有一个,他只要告诉工厂,他要什么样的就行了。
第一步:创建机器人接口
第二步:创建机器人实体类
第三步:创建工厂类
最后:创建工厂类实例,获取机器人
输出:
3、抽象工厂模式(Abstract Factory Pattern)
上面的简单的工厂类,如果要生产E罩杯的机器人,那么就创建一个RobotE继承接口IRobot就行了,但工厂类的switch里面的判断要增加一个case “E”的条件。为了改善并扩展工厂模式,就引入了抽象工厂模式。
优点:将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的工厂类里加代码,又要在具体的里面加代码。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
注意事项:产品族难扩展,产品等级易扩展。
还是举上面污污的例子:改进的地方其实是工厂,将每种机器人的生产落实到不同的工厂里面去生产
第一步:创建抽象的机器人类
第二步:创建机器人实体类
第三步:创建抽象工厂类
第四步:创建工厂的实体类
最后:创建抽象工厂获取实体工厂得到对应的机器人
输出:
4、原型模式(Prototype Pattern)
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
优点:
1、原型模式向客户隐藏了创建新实例的复杂性
2、原型模式允许动态增加或较少产品类。
3、原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
4、产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构
缺点:
1、每个类必须配备一个克隆方法
2、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
使用场景:
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
举个栗子:
第一步:创建原型抽象类
第二步:创建具体原型实体类
最后:实现克隆
输出:
5、备忘录模式(Memento Pattern)
又称标记(Token)模式。在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态(这是备忘录模式存在的根本原因)。
优点: 1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。 2、实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
使用场景: 1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。 (比如: 后悔药、打游戏时的存档、Windows 里的 ctrl + z、IE 中的后退、数据库的事务管理。)
举个栗子,实现过程:
第一步:创建需要备忘的实体类
第二步:创建备忘录
第三步:创建管理备忘录的实体类
第四步:创建发起备忘录实体类
最后:
输出: