C++设计模式:工厂方法模式(六)

1、定义与动机
  • 对象创建模式:通过对象创建模式绕开new,来避免对象(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
    • Factory Method
    • Abstract Factory
    • Prototype
    • Builder
  • 工厂模式定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
  • 动机
    • 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
    • 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"具体对象创建工作"的紧耦合带来的问题?
2、案例分析

MainForm类绑定一个Button按钮触发一个文件分割的事件。

2.1、普通设计方式
cpp 复制代码
class FileSplitter{
    void split(){
        // ...
    }
};

class MainForm: public Form{

    void button_event(){
        FileSplitter *fileSplitter = new FileSplitter();
        fileSplitter->split();
    }
};
  • 这种代码存在一定的问题,fileSplitter这个对象是具体的实现 不是一个抽象;假如需要根据分割文件的类型派生出各种音频、文本、二进制文件等等的分割,这里的代码很明显无法应对"变化",违背开闭原则

  • 其实违背开闭原则可以从一个很简单的方式去处理:策略模式,这个需求其实就可以很好的使用策略模式去解决

2.2、策略模式
  • 通过多态的形式来解决这一需求:MainForm里面组合一个ISplitter抽象接口,在使用是动态的传入一个对象,此时就有了运行时的多态!
cpp 复制代码
class ISplitter{
    virtual void split() = 0;
    virtual ~ISplitter(){}
};

class FileSplitter: ISplitter{
    virtual void split() override{
        // ...
    }
};

class VideoSplitter: ISplitter{
    virtual void split() override{
        // ...
    }
};

class MainForm: public Form{
private:
    ISplitter *splitter;
public:
    MainForm(ISplitter *iSplitter): splitter(iSplitter){

    }
    void button_event(){

        splitter.split();
    }
};

void process()
{
    MainForm mainForm(new FileSplitter());
    MainForm mainForm(new VideoSplitter());
}
3、工厂方法
  • 工厂方法模式是本节设计模式的核心,但是我觉得这个案例举例并不好,因为可以使用策略模式优化掉

  • 但是仔细一想,策略模式和工厂方法关注点并不一样。

3.1、优化代码(一)
  • 首先先把策略模式放在一边,把代码恢复到下面这个样子,这一份代码较比最开始的代码还是有一定的优化的,只是还是不够抽象!
  • 我们来分析下面这个代码存在的弊端问题:
    • 这一份代码核心点: ISplitter *splitter = new VideoSplitter();就是这个new语句
    • new对象这条语句,左半边已经优化好了是一个抽象,右半边是一个具体的实现,因此还是一个具体的实现,**右半边不够抽象!**这样就会导致是一个紧耦合的关系
    • 右半边不够抽象的原因:是因为是具体的new某个实现对象,也无法应对需求。就像一只猫,你没有缩小它的活动范围,使得它充斥在任何一个角落
cpp 复制代码
class ISplitter{
    virtual void split() = 0;
    virtual ~ISplitter(){}
};

class FileSplitter: ISplitter{
    virtual void split() override{
        // ...
    }

};

class VideoSplitter: ISplitter{
    virtual void split() override{
        // ...
    }

};

class MainForm: public Form{
public:
    MainForm(ISplitter *iSplitter): splitter(iSplitter){

    }
    void button_event(){
        ISplitter *splitter = new VideoSplitter();
//        ISplitter *splitter = new FileSplitter();
        splitter.split(..., ...);
    }
};

void process()
{
    MainForm mainForm(new FileSplitter());
    MainForm mainForm(new VideoSplitter());
}
3.2、工厂方法(二)
  • 工厂方法提倡的核心点是:在实现代码中不提倡使用new来具体指定某一个对象,而是将new这一过程向外传

  • 向外传的好处:使得这个实现变得抽象(赋值号右边)

  • 因此可以抽象出一个SplitterFactory接口,主要负责创建对象,具体的实现交给实现子类XXXSplitterFactory。

    • 第一个问题:为什么不把创建对象方法写在ISplitter接口中?因为要满足单一职责原则,强行写过去不单一

    • 第二个问题:是否满足开闭原则?满足,因为新加一个其他文件类型的分割类,只需要加XXXSplitter和XXXSplitterFactory。

    • 第三个问题:赋值号右边是具体的实现(不够抽象)吗?是一个抽象,完美解耦,只有运行时才知道具体的类型。

cpp 复制代码
class ISplitter{
    virtual void split() = 0;
    virtual ~ISplitter(){}
};

class SplitterFactory{
public:
    virtual ISplitter *CreateSplitter()=0;
    virtual ~SplitterFactory(){

    }
};

class FileSplitter: public ISplitter{
    virtual void split() override{
        // ...
    }
};

class VideoSplitter: ISplitter{
    virtual void split() override{
        // ...
    }
};


class FileSplitterFactory: public FileSplitter{
public:
    virtual ISplitter *CreateSplitter(){
        return new FileSplitter();
    }
};

class VideoSplitterFactory: public VideoSplitter{
public:
    virtual ISplitter *CreateSplitter(){
        return new VideoSplitter();
    }
};

class MainForm: public Form{
private:
    SplitterFactory *splitterFactory;
public:
    MainForm(SplitterFactory *_splitterFactory): splitterFactory(_splitterFactory){

    }
    void button_event(){
        ISplitter *splitter = splitterFactory->CreateSplitter();
        splitter.split();
    }
};

void process()
{
    MainForm mainForm(new FileSplitterFactory());
    MainForm mainForm(new VideoSplitterFactory());
}
4、总结
4.1 工厂方法总结
  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱
  • Factory Method模式通过面向对象的手法,将索要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合的关系。
  • Factory Method模式解决"单个对象"的需求变化,缺点在于要求创建方法、参数相同。
4.2、工厂模式与策略模式对比
工厂模式 策略模式
用途 工厂模式是创建型模式,它的作用是创建对象 策略模式是行为模式,它的作用是让一个对象在许多行为中选择一种行为
关注点 关注对象创建 关注行为的封装
解决问题 它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。 为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
透明度 黑盒子 白盒子
相关推荐
ll7788114 小时前
C++学习之路,从0到精通的征途:继承
开发语言·数据结构·c++·学习·算法
我不想当小卡拉米4 小时前
【Linux】操作系统入门:冯诺依曼体系结构
linux·开发语言·网络·c++
炎芯随笔4 小时前
【C++】【设计模式】生产者-消费者模型
开发语言·c++·设计模式
乌鸦9444 小时前
《类和对象(下)》
开发语言·c++·类和对象+
逐光沧海5 小时前
数据结构基础--蓝桥杯备考
数据结构·c++·算法·蓝桥杯
前进的程序员5 小时前
嵌入式开发中 C++ 跨平台开发经验与解决方案
开发语言·c++
菜一头包5 小时前
c++ std库中的文件操作学习笔记
c++·笔记·学习
吃个早饭7 小时前
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
c语言·c++·蓝桥杯
阿沁QWQ8 小时前
单例模式的两种设计
开发语言·c++·单例模式
六bring个六8 小时前
qtcreater配置opencv
c++·qt·opencv·计算机视觉·图形渲染·opengl