设计模式

设计模式

创建型模式

创建型模式(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运算符。

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

参考

相关推荐
myprogramc5 分钟前
十大排序算法
数据结构·算法·排序算法
记得早睡~9 分钟前
leetcode150-逆波兰表达式求值
javascript·算法·leetcode
qy发大财11 分钟前
跳跃游戏(力扣55)
算法·leetcode
BingLin-Liu14 分钟前
蓝桥杯备考:搜索算法之排列问题
算法·职场和发展·蓝桥杯
计算机小白一个17 分钟前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
curemoon1 小时前
理解都远正态分布中指数项的精度矩阵(协方差逆矩阵)
人工智能·算法·矩阵
柃歌1 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌1 小时前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
SKYDROID云卓小助手3 小时前
无人设备遥控器之如何分享数传篇
网络·人工智能·算法·计算机视觉·电脑
Lqingyyyy3 小时前
P2865 [USACO06NOV] Roadblocks G 与最短路的路径可重复的严格次短路
开发语言·c++·算法