李建忠设计模式之“对象创建”模式
文章目录
- 工厂方法模式(Factory Method)
- 定义
- 动机
- 结构图
- 代码
- 要点
- 总结
- 抽象工厂模式(Abstract Factory)
- 定义
- 动机
- 结构图
- 代码
- 要点
- 总结
- 原型模式(Prototype)
- 定义
- 动机
- 结构图
- 代码
- 要点
- 总结
- 构建器模式(Builder)
- 定义
- 动机
- 结构图
- 代码
- 要点
- 总结
通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
典型模式:Factory Method、Abstract Factory、Prototype、Builder
工厂方法模式(Factory Method)
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
——《设计模式》GoF
动机
- 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
- 如何应对这种变化? 如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?
结构图
代码
class IProduct{string name;
public:virtual void run() = 0;virtual ~IProduct(){}
};
class ProductA: public IProduct{virtual void run(){//...}
};
class ProductB: public IProduct{virtual void run(){//...}
};
class IFactory{
public:virtual IProduct * createProduct() = 0;virtual ~IFactory(){}
};
class ProductAFactory : public IFactory{
public:virtual IProduct * createProduct() {return new ProductA();}
};
class ProductBFactory : public IFactory{
public:virtual IProduct * createProduct() {return new ProductB();}
};
要点
- Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
- Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
- Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
总结
Factory Method模式封装了对象的创建工作,从而避免了客户程序的new操作,只需调用工厂方法即可,解决了客户程序和调用对象之间的紧耦合。
抽象工厂模式(Abstract Factory)
定义
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
——《设计模式》GoF
动机
- 在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
- 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作的紧耦合?
结构图
代码
// 假设产品A实现x和产品B只能和对应的实现x搭配,不匹配就会产生错误
// 产品A基类
class IProductA{string name;
public:virtual void run() = 0;virtual ~IProductA(){}
};
// 产品A实现1
class ProductA1: public IProductA{virtual void run(){//...}
};
// 产品A实现2
class ProductA2: public IProductA{virtual void run(){//...}
};
// 产品B基类
class IProductB{string name;
public:virtual void run() = 0;virtual ~IProductB(){}
};
// 产品B实现1
class ProductB1: public IProductB{virtual void run(){//...}
};
// 产品B实现2
class ProductB2: public IProductB{virtual void run(){//...}
};// 工厂基类
class IProductFactory{
public:virtual IProductA * createProductA() = 0;virtual IProductB * createProductB() = 0;virtual ~IProductFactory(){}
};
// 工厂1:生产产品实现1
class ProductBFactory1 :public IProductFactory{
public:virtual IProductA * createProductA() {return new ProductA1();}virtual IProductB * createProductB() {return new ProductB1();}
};
// 工厂2:生产产品实现2
class ProductBFactory2 :public IProductFactory{
public:virtual IProductA * createProductA() {return new ProductA2();}virtual IProductB * createProductB() {return new ProductB2();}
};int main(int argc, char const *argv[]){// 新建一类产品IProductFactory pf1 = new ProductBFactory1;IProductA = pf1.createProductA();IProductB = pf1.createProductB();return 0;
}
要点
- 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
- “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
- Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
总结
Abstract Factory其实和Factory Method模式类似,只不过他将一系列关联性非常强的对象创建工作封装到了一个类中,这样可以一定程度上避免客户程序创建不匹配的对象进行操作。
原型模式(Prototype)
定义
使用原型实例(仅供克隆)指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
——《设计模式》GoF
动机
- 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
- 如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efVMMPAA-1664189552211)(http://qny.cwnest.top/designPattern/原型模式类图.png)]
代码
// 抽象类
class ISplitter{
public:virtual ISplitter* clone()=0;//通过克隆自己来创建对象virtual ~ISplitter(){}
};// 具体类
class BinarySplitter : public ISplitter{
public:virtual ISplitter* clone(){// C++调用拷贝构造函数,其他语言实现方式可能不同// 需要实现深拷贝return new BinarySplitter(*this);}
};class TxtSplitter : public ISplitter{
public:virtual ISplitter* clone(){return new TxtSplitter(*this);}
};
class MainForm : public Form
{ISplitter* prototype;//原型对象
public:MainForm(SplitterFactory* prototype){this->prototype=prototype;}void Button1_Click(){ISplitter * splitter = prototype->clone();//克隆原型splitter->split();//使用克隆对象进行操作}
};
要点
- Prototype模式同样用于隔离对象的使用者和**具体类型(易变类)**之间的耦合关系,它同样要求这些“易变类”拥有稳定的接口。
- Prototype模式对于“如何创建易变类的实体对象“采用原型克隆的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方clone。
- Prototype模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。(c++用拷贝构造函数即可)
总结
原型模式一般来说使用场景较少,适用于工厂方法创建对象比较复杂繁琐的情况,它利用已经处于某种状态的原型对象克隆出新的对象,从而避免了复杂的创建工作,只需在克隆对象上进行相对少量的操作就能达到目的。
构建器模式(Builder)
定义
将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
——《设计模式》GoF
动机
- 在软件系统中,有时候面临着一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
结构图
代码
// 房子抽象基类
class House{//...
};
// 房子构建类抽象基类
class HouseBuilder{
public:House *GetResult(){return pHouse;}virtual ~HouseBuilder() {}
protected:House *pHouse;virtual void BuildPart1() = 0;virtual void BuildPart2() = 0;virtual void BuildPart3() = 0;virtual void BuildPart4() = 0;virtual void BuildPart5() = 0;
}// 负责House类的创建流程(也可以不单独声明成类,放在HouseBuilder中)
class HouseDirector{HouseBuilder *pHouseBuilder;
public:HouseDirector(HouseBuilder *hb){this->pHouseBuilder = hb;}House *Construct(){pHouseBuilder->BuildPart1();for (int i = o; i < 4; i++){pHouseBuilder->BuildPart2();}bool flag = pHouseBuilder->BuildPart3();if (flag){pHouseBuilder->BuildPart4();}pHouseBuilder->BuildPart5();return pHouseBuilder->GetResult();}
};// 具体实现(石头房子)
class StoneHouse : public House {// ...
};
class StoneHouseBuilder : public HouseBuilder{
protected:virtual void BuildPart1(){// pHouse->Part1 = . . ;}virtuat void BuildPart2() {}virtual void BuildPart3() {}virtual void BuildPart4() {}virtual void BuildPart5() {}
}int main(){HouseBuilder stoneHouseBuilder = new StoneHouseBuilder();HouseDirector houseDirector = new HouseDirector(stoneHouseBuilder);House* house = houseDirector.Construct();//得到石头房子
}
要点
- Builder模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
- 变化点在哪里,封装哪里——Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。
- 在Builder模式中,要注意不同语言中构造器内调用虚函数的差别(C++Vs.C#)。C++不能直接在构造器中调用虚函数,而C#、java等高级语言可以。
tips:为什么C++中父类对象构造函数调用虚函数不能实现多态?
因为在C++中子类初始化时要先调用父类的构造函数,如果在父类构造函数中调用一个虚函数当然无法调用子类对于父类虚函数的重载实现(因为此时子类还没有创建)。
总结
Builder模式和Template Method模式非常类似。特殊点在于Builder模式实在初始化类的时候拥有稳定的构建方式。
李建忠设计模式之“对象创建”模式相关推荐
- 李建忠设计模式之“单一职责”模式
文章目录 装饰器模式(Decorator) 定义 动机 结构图 代码 要点 总结 桥方法模式(Bridge) 定义 动机 结构图 代码 要点 总结 在软件组件的设计中,如果责任划分的不清晰,使用继承得 ...
- 李建忠设计模式之“组件协作”模式
文章目录 模板方法模式(Template Method) 定义 动机 结构图 代码 要点 总结 策略模式(Strategy) 定义 动机 结构图 代码 要点 总结 观察者模式(Observer/Eve ...
- 李建忠设计模式之”行为变化“模式
文章目录 命令模式(Command) 定义 动机 结构图 代码 要点 总结 访问器模式(visitor) 定义 动机 结构图 代码 要点 总结 在组件的构建过程中,组件行为的变化经常导致组件本身剧烈的 ...
- 李建忠设计模式之”领域规则“模式
文章目录 解析器模式(Interpreter) 定义 动机 结构图 代码 要点 总结 在特定领域中,某些变化虽然频繁,但可以抽象为某种规则.这时候,结合特定领域,将问题抽象为语法规则,从而给出在该领域 ...
- 李建忠设计模式——策略模式Strategy
目录 1.策略模式定义 1.动机 2.模式定义 3.结构 2.实现例子 1.问题描述 2.代码实现 3.要点总结 4.参考 1.策略模式定义 1.动机 软件构建过程中,某些对象使用的算法可能多种多样, ...
- 李建忠设计模式——观察者模式
1.观察者模式(Observer/Event) 1.动机 在软件构建过程中,需要为某些对象建立一种"通知依赖关系"--一个对象(目标)的状态发生改变,所有的依赖对象(观察者对象)都 ...
- 李建忠设计模式-组件协作模式-模板方法模式
目录 1.前言 2.模板方法模式(Template Method) 1.动机 2.例子 3.定义 1.结构图 2.模板方法模式适用情形 3.模式特点 参考 1.前言 现代软件专业分工后的第一个结果是& ...
- 清华李建忠设计模式课程感想
最近又看了一波设计模式的东西,又有一些新的认识,设计模式一般是重构到模式,模式不是一蹴而就的,很多最开始在实现产品经理的需求时,第一版是不太能识别模式的,当然如果后期的迭代需求方向明确也可做提前设计, ...
- 李建忠设计模式之总结
总结 一个目标:管理变化,提高复用! 两个手段:分解 && 抽象 八大原则 依赖倒置原则(DIP) 开放封闭原则(OCP) 单一职责原则(SRP) Liskov 替换原则(LSP) 接 ...
最新文章
- 支持取消操作和暂停操作的Backgroundworker
- fetch 自动加cookie_如何在shell中动态获取chrome浏览器的cookie信息
- 探究platform_driver中“多态”思想
- SprinMVC 控制器忽略静态资源
- jquery对url中的中文解码
- CustomValidator控件用法
- 【HTML】【简易电子相册】overflow:hidden;
- python实现sm3加密算法
- 【历史上的今天】10 月 11 日:域名 baidu.com 问世;三星 Galaxy Note 7 爆炸门告一段落;图灵奖数据库先驱诞生
- 电脑调分辨率黑屏了怎么办_Win10调分辨率后出现黑屏提示“超出工作频率范围”怎么办...
- java将Word转换成PDF
- FMI飞马网线上直播-《ELK Stack深入浅出》
- python多边形的绘制教程_使用Python matplotlib绘制3D多边形
- Java多线程复习整理(二)
- 谷歌:科技让世界更美好
- linux硬件之磁盘运行读写原理
- Linux NetworkManager网络服务详解
- 数据结构学习笔记——线性表逻辑结构和顺序存储结构
- 家用宽带公网ipv4/ipv6搭建服务(常见两种网络模式)超详细
- Vue3.0+TS+Element-plus实现(若依版后台管理系统)