个人博客网页设计,网站优化的优势,网页浏览器打开,在线设计logo免费网站文章目录 1. “对象创建模式”模式1.1 典型模式 2. 动机#xff08;Motivation#xff09;3. 代码演示Factory Method工厂方法模式3.1 常规方法3.2 面向接口的编程3.2.1 FileSplitter1.cpp3.2.2 MainForm1.cpp 3.3 Factory Method工厂方法3.3.1 ISplitterFactory.cpp3.3.2 Ma… 文章目录 1. “对象创建模式”模式1.1 典型模式 2. 动机Motivation3. 代码演示Factory Method工厂方法模式3.1 常规方法3.2 面向接口的编程3.2.1 FileSplitter1.cpp3.2.2 MainForm1.cpp 3.3 Factory Method工厂方法3.3.1 ISplitterFactory.cpp3.3.2 MainForm2.cpp3.3.3 FileSplitter2.cpp 4. 模式定义5. 结构6. 要点总结7. 其他参考 本篇将会介绍Factory Method工厂方法模式其属于一个新的类别将其归结到“对象创建模式”该模式的简介如下
1. “对象创建模式”模式
通过“对象创建” 模式绕开new来避免对象创建new过程中所导致的紧耦合依赖具体类从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
1.1 典型模式
Factory MethodAbstract FactoryPrototypeBuilder
这四个模式非常接近解决的是同一个问题只不过这些问题在演化过程中会有细微的差别需要四个不同的模式进行应对。
2. 动机Motivation 在软件系统中经常面临着创建对象的工作由于需求的变化需要创建的对象的具体类型经常变化。 如何应对这种变化如何绕过常规的对象创建方法(new)提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合
对C设计模式_05_Observer 观察者模式中的文件分割器的代码抽象将观察者模式等跟本篇介绍内容不相关的去除只突出跟“对象创建模式”相关的代码。
3. 代码演示Factory Method工厂方法模式
3.1 常规方法
常规的方法是创建一个Splitter类在类中定义一个核心的split方法在客户端收集参数之后创建一个对象通过对象调用方法完成分割。
这种方法存在什么问题呢
假如我们在一个变化场景看问题一般意义上一个类型需要看到未来变化的需求这个时候就需要做抽象类或者接口这是我们最早讲的设计原则-面向接口的编程。
3.2 面向接口的编程
面向接口的编程告诉我们以一个对象的类型往往应该声明为一个抽象类或者接口而不应该声明为具体的类一旦声明为具体的类就意味着没有支持未来的变化。
假设上面的代码中只支持二进制文件的分割但是未来也可能支持文本文件的分割或者图片文件或视频文件的分割等。那么代码就变成如下所示
3.2.1 FileSplitter1.cpp
class ISplitter{
public:virtual void split()0;virtual ~ISplitter(){}
};class BinarySplitter : public ISplitter{};class TxtSplitter: public ISplitter{};class PictureSplitter: public ISplitter{};class VideoSplitter: public ISplitter{};3.2.2 MainForm1.cpp
class MainForm : public Form
{TextBox* txtFilePath;TextBox* txtFileNumber;ProgressBar* progressBar;public:void Button1_Click(){//面向接口编程的最基础表现形式变量声明为抽象基类ISplitter * splitternew BinarySplitter();//依赖具体类splitter-split();}
};上述即为面向接口所编写的程序之前介绍的模式背后都有一个抽象基类这是面向对象设计模式的基础。
为什么要实现面向接口编程
设计原则-依赖倒置原则依赖抽象不依赖实现细节 ISplitter * splitternew BinarySplitter();//依赖具体类ISplitter * splitter是抽象依赖而new BinarySplitter()是细节依赖仍然存在细节依赖也是不可以的简单来说MainForm 在编译时总体还是依赖BinarySplitter存在才能编译通过的这就是编译时的细节依赖这就违背了设计原则中的依赖倒置原则。这个问题如何解决呢
再回过头看“对象创建模式”模式中提到的“通过“对象创建” 模式绕开new来避免对象创建new”为什么要避免对象创建new的原因也就是上面提到new BinarySplitter()带来的细节依赖。“它是接口抽象之后的第一步工作”可以理解为它是面向接口编程必然提出的需求也就是面向接口编程不能只管ISplitter * splitter的抽象依赖而不管new BinarySplitter()的细节依赖两边都要变为接口变为依赖抽象。
想一想在C中创建对象的方法
由于抽象类是不允许创建对象的利用new和栈上创建对象的方法替换等号右边实现右边为抽象的方法也是不可行的。
那么是否可以采用一种方法来返回一个对象并且利用virtual实现运行时依赖这就引出本篇的重点Factory Method工厂方法。
3.3 Factory Method工厂方法
3.3.1 ISplitterFactory.cpp
//抽象类
class ISplitter{
public:virtual void split()0;virtual ~ISplitter(){}
};//工厂基类
class SplitterFactory{
public:virtual ISplitter* CreateSplitter()0;virtual ~SplitterFactory(){}
};
3.3.2 MainForm2.cpp
class MainForm : public Form
{SplitterFactory* factory;//工厂public:MainForm(SplitterFactory* factory){this-factoryfactory;}void Button1_Click(){//现在的返回值为ISplitter但是真正创建的对象交给SplitterFactory未来其中可以放具体的factory即FileSplitter2.cpp具体工厂内容 ISplitter * splitterfactory-CreateSplitter(); //多态newsplitter-split();}
};其中Button1_Click()是可以多次点击的但SplitterFactory* factory;只需要一个即可代码如上MainForm中不需要具体指定具体的工厂通常通过以下代码外接传递进来的一个具体的factory例如BinarySplitterFactoryISplitter * splitterfactory-CreateSplitter();创建的就是一个BinarySplitter这样就可以反复创建BinarySplitter这个地方的形式我们称为多态new。 MainForm(SplitterFactory* factory){this-factoryfactory;}此时可能会有人想传进来的具体的factory在其他地方也要创建也会对具体类产生依赖这是对的但是在MainForm没有对具体类至于MainForm以外的是不归MainForm管的。
面向对象设计模式的松耦合设计很多情况下不是消灭变化依赖具体类而是将其赶到局部的地方。大家可以将变化比作一只猫将其关到笼子里而不是让它在你的代码里面跳来跳去。
3.3.3 FileSplitter2.cpp
//具体类
class BinarySplitter : public ISplitter{};class TxtSplitter: public ISplitter{};class PictureSplitter: public ISplitter{};class VideoSplitter: public ISplitter{};//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new BinarySplitter();}
};class TxtSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new TxtSplitter();}
};class PictureSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new PictureSplitter();}
};class VideoSplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new VideoSplitter();}
};上面代码就是一个完整的Factory Method工厂方法模式。
4. 模式定义
定义一个用于创建对象的接口让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟目的解耦手段虚函数到子类。
——《设计模式》GoF
结合代码来看“定义一个用于创建对象的接口”指的 就是以下代码具体即为virtual ISplitter* CreateSplitter()0;
//工厂基类
class SplitterFactory{
public:virtual ISplitter* CreateSplitter()0;virtual ~SplitterFactory(){}
};“让子类决定实例化哪一个类”即为以下代码
//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:virtual ISplitter* CreateSplitter(){return new BinarySplitter();}
};
......5. 结构 上图是《设计模式》GoF中定义的Factory Method工厂方法的设计结构。结合上面的代码看图中最重要的是看其中稳定和变化部分也就是下图中红框和蓝框框选的部分。 6. 要点总结
Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型紧耦合关系(new)会导致软件的脆弱。Factory Method模式通过面向对象的手法多态将所要创建的具体对象工作延迟到子类从而实现一种扩展而非更改的策略较好地解决了这种紧耦合关系。Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
第二条中的扩展也就是增加对应的factory即可。延迟而非更改最早的代码中一旦需求发生变化就需要在Mainform中更改ISplitter * splitternew BinarySplitter();//依赖具体类,现在需求变化之后Mainform中ISplitter * splitterfactory-CreateSplitter(); 就不需要改变只需要增加子类和子类工厂传给Mainform即可。
7. 其他参考
C设计模式——工厂方法模式