设计模式

设计模式

创建型模式

创建型模式(Creational Pattern)主要关注对象创建过程的灵活性和可复用性

工厂方法

  • 工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型
  • 如果无法预知对象确切类别及其依赖关系时,可使用工厂方法
  • 工厂方法模式建议使用特殊的工厂 方法代替对于对象构造函数的直接调用 (即使用 new运算符)。 不用担心, 对象仍将通过 new运算符创建, 只是该运算符改在工厂方法中调用罢了。 工厂方法返回的对象通常被称作 "产品"。

  • 工厂方法(Factory Method)模式适用于将对象的创建和使用分离,并希望尽可能多地复用现有代码来处理新型对象的情景。

    c++ 复制代码
    class Network {
    public:
      virtual ~Network() { cout << "Network destroyed" << endl; }
      virtual string getNetworkType() const = 0;
    };
    class CNN : public Network {
    public:
        string getNetworkType() const override {
            return "CNN";
        }
    };
    
    class GAN : public Network {
    public:
        string getNetworkType() const override {
            return "GAN";
        }
    };
    • 纯虚函数getNetworkType()用来返回网络的类型

抽象工厂

  • 抽象工厂(Abstract Factory)适用于需要创建许多种一系列相互依赖的对象的情景。
  • 如果代码需要与多个不同系列的相关产品交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建,在这种情况下,你可以使用抽象工厂
  • 工厂方法与抽象工厂的根本区别在于工厂方法是"方法",抽象工厂是"对象"。具体地,工厂方法的目的在于用基类的不同子类来表示不同的对象;抽象工厂只需要关心如何创建一系列相互依赖的对象,可以理解为一种包含很多工厂方法的对象。

抽象工厂模式建议为系列中的每件产品明确声明接口 (例如椅子、 沙发或咖啡桌)。 然后, 确保所有产品变体都继承这些接口。 例如, 所有风格的椅子都实现 椅子接口; 所有风格的咖啡桌都实现 咖啡桌接口, 以此类推

例如, 现代家具工厂Modern­Furniture­Factory只能创建 现代椅子Modern­Chair 、 现代沙发Modern­Sofa和 现代咖啡桌Modern­Coffee­Table对象。

  • 在两个Network的子类里,我们调用Dataset接口的方式是相同的:dataset.getDatasetName(),区别在于我们需要在CNN的实现当中只关心CNN的数据预处理,在GAN当中只关心GAN的数据预处理

    python 复制代码
    class Dataset {
    public:
        virtual ~Dataset() { cout << "Dataset destroyed" << endl; }
        virtual string getDatasetName() const = 0;
    };
    
    class ImageNet : public Dataset {
    public:
        string getDatasetName() const override {
            return "ImageNet";
        }
    };
    
    class CelebA : public Dataset {
    public:
        string getDatasetName() const override {
            return "CelebA";
        }
    };
    
    class Network {
    public:
        virtual ~Network() { cout << "Network destroyed" << endl; }
        virtual string getNetworkType() const = 0;
        virtual string giveMeADataset(const Dataset& dataset) const = 0;
    };
    
    class CNN : public Network {
    public:
        string getNetworkType() const override {
            return "CNN";
        }
        string giveMeADataset(const Dataset& dataset) const override {
            const string dataset_name = dataset.getDatasetName();
            return "I am training a CNN with " + dataset_name;
        }
    };
    
    class GAN : public Network {
    public:
        string getNetworkType() const override {
            return "GAN";
        }
        string giveMeADataset(const Dataset& dataset) const override {
            const string dataset_name = dataset.getDatasetName();
            return "I am training a GAN with " + dataset_name;
        }
    };
  • 抽象工厂 是一种创建型设计模式, 它能创建一系列相关或相互依赖的对象, 而无需指定其具体类。什么是 "系列对象"? 例如有这样一组的对象: 运输工具+ 引擎+ 控制器 。 它可能会有几个变体:

    1. 汽车+ 内燃机+ 方向盘
    2. 飞机+ 喷气式发动机+ 操纵杆

    如果你的程序中并不涉及产品系列的话, 那就不需要抽象工厂。

生成器

生成器(Builder)模式适用于需要分很多步骤创建不同对象的情景。也就是说我所创建的对象可以由许多重复性的基本组件构成。

  • 基于神经网络的分类模型,具体的结构可以有很多种,例如只有1个全连通层的线性模型、包含多个全连通层的MLP、以及同时包含多个卷积层和全连通层的CNN等。这些不同的模型都是由"全连通层"和"卷积层"这两个基本单元构成的

    python 复制代码
    class Builder {
    public:
        virtual ~Builder() { cout << "Builder destroyed" << endl; }
        virtual void createLinearLayer() const = 0;
        virtual void createConvLayer() const = 0;
        virtual void createLossLayer() const = 0;
    };
  • 定义模块化组件进行组装

原型

原型(Prototype)模式适用于需要复制复杂的对象,并希望新复制的对象独立于原来的代码的情景。

  • clone()接口就是原型模式的关键所在

单例

单例(Singleton)模式适用于一个类只需要一个实例的情景。抽象工厂模式、生成器模式和原型模式都可以用单例模式实现

  • 我们一方面要避免在代码中显示地对模型进行复制(否则内存会爆掉),另一方面在设计模型的接口时也要保证其他人在调用我们的接口时不会随意地复制模型

    c++ 复制代码
    class Model {
    private:
        Model() {}
        ~Model() {}
    protected:
        Model(const string id) : model_id(id) {}
        static Model* model;
        string model_id;
    public:
        Model(const Model&) = delete;
        Model(Model&&) = delete;
        void operator=(const Model&) = delete;
        void operator=(Model&&) = delete;
    
        void train() {
            cout << "Training done with " + model_id + "\n";
        }
    
        static Model* getInstance(const string& id);
        static Model& getInstanceSafe(const string& id);
    };
    
    
    Model* Model::model = nullptr;
    Model* Model::getInstance(const string& id) {
        if (model == nullptr)
            model = new Model(id);
        return model;
    }
  • 我们只希望Model自己有权对模型进行创建和删除,所以把constructordestructor声明为private。另外,我们不希望Model的调用者对模型进行复制,所以需要禁用其copy constructormove constructorcopy assignment operatormove assignment operator

  • 所有单例的实现都包含以下两个相同的步骤:

    • 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。

    • 新建一个静态构建方法作为构造函数。 该函数会 "偷偷" 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

参考

相关推荐
蹉跎x1 小时前
力扣1358. 包含所有三种字符的子字符串数目
数据结构·算法·leetcode·职场和发展
rainoway1 小时前
CRDT宝典 - yata算法
前端·分布式·算法
巫师不要去魔法部乱说2 小时前
PyCharm专项训练4 最小生成树算法
算法·pycharm
IT猿手2 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解GLSMOP1-GLSMOP9及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·算法·机器学习·matlab·强化学习
阿七想学习2 小时前
数据结构《排序》
java·数据结构·学习·算法·排序算法
王老师青少年编程2 小时前
gesp(二级)(12)洛谷:B3955:[GESP202403 二级] 小杨的日字矩阵
c++·算法·矩阵·gesp·csp·信奥赛
Kenneth風车3 小时前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类
eternal__day3 小时前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
APP 肖提莫3 小时前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
OTWOL3 小时前
两道数组有关的OJ练习题
c语言·开发语言·数据结构·c++·算法