【设计模式】Head First 设计模式——工厂方法模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。

设计思想

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

动机

在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。

如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"具体对象创建工作"的紧耦合?

Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。

Factory Method模式通过面向对象的收发,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种耦合关系。

Factory Method 模式解决"单个对象"的需求变化。缺点在于创建方法、参数需要相同。

业务场景

在 MainForm 中需要对文件进行分解操作,但是分解的文件可能是二进制文件,文本文件,图片文件等等,这时候我们需要在 MainForm 创建对应的对象,然后调用分解函数。

一个非常直观的思路是:

C++ 复制代码
class ISplitter {
public:
    virtual void split() = 0;
    virtual ~ISplitter() {
    }
};

class BinarySplitter : public ISplitter {
//实现分解二进制文件
};

class TxtSplitter : public ISplitter {
//实现分解TXT文件
};

class PictureSplitter : public ISplitter {
//实现分解图片文件
};

class VideoSplitter : public ISplitter {
 //实现分解视频文件   
};

class MainForm : public Form {
public:
    void Button1_Click() {
        ISplitter* splitter = new BinarySplitter();  
        splitter->split();
    }
};

这是很自然的一种写法,问题的关键在于这一句代码:

C++ 复制代码
ISplitter* splitter = new BinarySplitter();  

在等号的左边,是一个抽象类,属于抽象依赖(编译时依赖),但是等号的右边,是一个具体类,属于细节依赖。根据依赖倒置原则,抽象不应该依赖于细节,而这种写法很明显违背了这种原则。

下面看看使用工厂模式应该怎么去实现:

代码案例

编写专门的工厂类,再编写具体的工厂子类。在具体操作的 MainForm 中通过构造把子类对象传入。用多态的方式,避免了 MainForm 中的固定。

C++ 复制代码
// 抽象类
class ISplitter {
public:
    virtual void split() = 0;
    virtual ~ISplitter() {
    }
};

// 工厂基类
class SplitterFactory {
public:
    // 虚函数,延迟到运行时依赖
    virtual ISplitter* CreateSplitter() = 0;
    virtual ~SplitterFactory() {
    }
};//创建一个工厂类,专门负责对象的实例化

// 具体类
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();
    }
};

// MainForm 没有具体类的依赖
// 只有抽象的类的依赖
// 把依赖具体类转移了
class MainForm : public Form {
    SplitterFactory* factory;  // 含有工厂成员

public:
    MainForm(SplitterFactory* factory) {
        this->factory = factory;
    }//想要实例化什么样的对象,由运行时决定

    void Button1_Click() {
        ISplitter* splitter = factory->CreateSplitter();  // 多态new
        splitter->split();
    }
};
相关推荐
纪念 22923 分钟前
C++ 算法基础 (差分)
开发语言·c++·算法
用户624293196623 小时前
告别 Electron 臃肿与 Wireshark 老化界面:用 Rust + Tauri 2.0 构建多总线网络与现场总线深度分析仪 Omni-Probe
设计模式
是2的10次方啊5 小时前
设计模式与生活㉒:暖气热不热,得一间一间摸过去
设计模式
ShineWinsu5 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽6 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
bigbread10 小时前
迭代器模式-在区域健康档案导出中的实战应用
设计模式
汉克老师11 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
装不满的克莱因瓶12 小时前
设计模式之策略模式核心概念和应用场景
java·后端·设计模式·架构·系统架构·策略模式
晴天的雨.99212 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂13 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛