首页 > 其他分享 >[设计模式] Factory Method

[设计模式] Factory Method

时间:2022-11-25 20:32:26浏览次数:46  
标签:Factory virtual class SplitterFactory Method ISplitter new 设计模式 public


[设计模式] Factory Method

动机

  • 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
  • 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?

模式定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。 ——《设计模式》GoF

SHOW ME THE CODE

​MainForm1.cpp​

class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;

public:
void Button1_Click(){

string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());

FileSplitter * splitter //声明成具体的类,没有考虑未来的变化
= new FileSplitter(filePath,number);
splitter->split();

}
};

以静态的视角看过去其实没什么问题,但是以未来的视角来看实际上存在问题。

我们可以用抽象类/接口的方法来将问题暴露出来,回忆设计原则:面向接口编程

针对接口编程,而不是针对实现编程

  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口(不要绝对化了,这里主要指业务类)
  • 客户程序无需获知对象的具体类型,需要知道对象所具有的接口
  • 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案
  • 产业强盛的标志是接口标准化,接口标准化的本质是分工协作

写一个抽象类,然后考虑未来可能的扩展

//抽象类
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{

};

那么​​MainForm​​变为

class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;

public:
void Button1_Click(){
//去掉了一些没啥影响的代码
ISplitter * splitter=//依赖抽象了
new BinarySplitter();//依赖具体类

splitter->split();

}
};

在接口抽象之后还有个问题,对象创建(new)依赖了具体类

ISplitter * splitter=//依赖抽象了
new BinarySplitter();//依赖具体类,违反了依赖倒置原则

根据依赖倒置(DIP):编译时依赖

  • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)
  • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)

目前我们的思路大致如下

面向接口编程原则发现问题->接口抽象–>依赖倒置原则发现问题–>解决创建对象依赖具体类

考虑创建对象的方法

  • 直接创建一个抽象类?不可以,C++不允许这么做
  • 在堆上​​new​​一个对象?那就是上面代码暴露出的问题
  • 用一个方法来返回一个对象(实际上可以认为​​new​​也是一个方法)
class SplitterFactory{
public:
ISplitter* CreateSpliter(){
return new BinarySplitter();
}
}
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;

public:
void Button1_Click(){

SplitterFactory factory;
ISplitter * splitter=
factory.CreateSplitter();
splitter->split();

}
};

这样问题解决了吗?有改善但没完全解决

注意目前的依赖指的是编译时依赖

​splitter​​​依赖​​SplitterFactory​​​,​​SplitterFactory​​​依赖​​BinarySplitter​​​,最终​​splitter​​​还是依赖​​BinarySplitter​

那么考虑一下有没有运行时依赖的玩意:​​virtual​​函数

//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSpliter()=0;
virtual ~SplitterFactory(){}//任何一个纯虚基类都需要一个虚的析构函数
}
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;

public:
void Button1_Click(){

SplitterFactory* factory;//依赖交给未来
ISplitter * splitter=
factory->CreateSplitter(); //多态new,用指针的方式调用纯虚基类
splitter->split();

}
};

​virtual​​函数实际上就是一种延迟的手法,我们将依赖交给了未来

​ISplitterFactory.cpp​

//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};


//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};

​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();
}
};

​MainForm2.cpp​

class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:

MainForm(SplitterFactory* factory){//未来从外界传递某一个具体的SplitterFactory
this->factory=factory;
}

void Button1_Click(){


ISplitter * splitter=
factory->CreateSplitter(); //多态new

splitter->split();

}
};

现在​​MainForm​​解决了依赖具体类的问题

但是依赖具体类的问题真的完全被消灭了吗?可能没有。实际上我们的面向对象设计模式很多时候并不能消灭变化,但是我们可以把变化赶到某一个局部的地方。

在这个例子当中,我们真正解决的问题是变化在整个类设计的各个地方穿插,而非完全消灭变化

结构设计

红色稳定,蓝色变化

​MainForm​​的创建现在依赖红色稳定的部分

[设计模式] Factory Method_工厂方法模式

要点总结

  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
  • Factory Method模式通过面向对象的手法(多态),将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
  • Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同


标签:Factory,virtual,class,SplitterFactory,Method,ISplitter,new,设计模式,public
From: https://blog.51cto.com/u_15891800/5887737

相关文章

  • [设计模式] Template Method
    TemplateMethod动机在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务......
  • 设计模式你怎么看?--抽象工厂模式
    一 前言在设计模式中有简单工厂,工厂方法,抽象工厂,这三种工厂方法,各自有各自的特点,但有都有共同的特点工厂(Factory)都是围绕着工厂类转,这篇只写"抽象工厂"相关的内......
  • 设计模式——模板方法模式
    对数据库的操作一般包括连接、打开、使用、关闭等步骤,在数据库操作模板类中我们定义了connDB()、openDB()、useDB()、closeDB()四个方法分别对应这四个步骤。对于不同类型......
  • Dubbo源码-06-ProxyFactory
    作用生产者将要导出的目标对象封装(代理技术或者反射技术)成Invoker对象一接口@SPI("javassist")publicinterfaceProxyFactory{/***createproxy.......
  • 设计模式
    单例模式:确保全局只有一个该类的实例预加载:占用内存,将类的实例化私有,在类中声明一个静态的实例。外部可以直接调用。懒加载:无需占用内存,将类的实例化私有,且在类中创建一......
  • Java: Methods
    publicclassMain{staticvoidmyMethod(){System.out.println("Ijustgotexecuted!");}publicstaticvoidmain(String[]args){myMethod();......
  • Java 设计模式:工厂模式
    目录工厂模式(FactoryPattern)实现简单工厂模式示例工厂方法模式示例抽象工厂模式示例参考工厂模式(FactoryPattern)所属:创建型模式,适用时机:我们明确地计划不同条件下创建......
  • 设计模式——2、原型模式
     在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多......
  • java23种设计模式概述总结
    软件设计模式的意义:它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠......
  • IIS上Put操作出现HTTP Error 405.0 - Method Not Allowed 解决方法
      1、系统本地开发环境运行正常,在部署到服务器之后出现Put请求报405 -MethodNotAllowed错误。错误情况如下图: 2、通过分析,为WebDAV插件导致。WebDAV是超......