• 【设计模式】创建者模式_工厂、抽象工厂、建造者


    设计模式六大原则

    • 开闭原则(Open Close Principle)

    开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码。

    1. 单一职责原则

    不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。

    1. 里氏替换原则

    里氏代换原则(Liskov Substitution Principle LSP)中说,任何基类可以出现的地方,一定可以用其子类替换。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

    1. 依赖倒换原则

    面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

    1. 接口隔离原则

    每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

    1. 迪米特法则(最少知道原则)

    一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。

    1. 合成复用原则

    尽量首先使用合成/聚合的方式,而不是使用继承。

    创建型模式

    1. 工厂模式

    简单工厂 工厂方法模式 抽象工厂模式

    有一家物流公司,可以提供不同类型的运输工具,进行物流运输。客户要走陆运,就从公司里要一辆卡车,要海运就从公司要一艘船

    enum VTYPE {SHIP, TRUCK};     
    class Vehicles
    {    
    public:    
        virtual void Show() = 0;  
    };    
    //陆运    
    class Truck: public Vehicles    
    {    
    public:    
        void Show() { cout<<"This is a truck"<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 要增加一个新的载具类型,需要修改工厂类,违背开闭原则

    所以出现了工厂方法,不再通过修改工厂实现,而实创建新的工厂

    • 模式定义
    • 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使得一个类的实例化延迟到子类完成。
    #include 
    using namespace std;
    
    class Vehicles
    {
    public:
        virtual void Show() = 0;
    };
    //陆运    
    class Truck : public Vehicles
    {
    public:
        void Show() { cout << "This is a truck" << endl; }
    };
    //海运    
    class Ship : public Vehicles
    {
    public:
        void Show() { cout << "This is a ship" << endl; }
    };
    class Factory
    {
    public:
        virtual Vehicles* CreateVehicle() = 0;
    };
    //生产船的工厂    
    class FactoryShip : public Factory
    {
    public:
        Ship* CreateVehicle() { return new Ship(); }
    };
    //生产卡车的工厂    
    class FactoryTruck : public Factory
    {
    public:
        Truck* CreateVehicle() { return new Truck(); }
    };
    
    int main()
    {
        FactoryTruck *m_TruckFactory = new FactoryTruck();
        FactoryShip *m_ShipFactory = new FactoryShip();
    
        Vehicles* m_Truck = m_TruckFactory->CreateVehicle();
        m_Truck->Show();
    
        Vehicles* m_Ship = m_ShipFactory->CreateVehicle();
        m_Ship->Show();
    
        return 0;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 问题在于 每增加一种产品,就会增加一个工厂类

    现在公司业务升级,提供了更大载荷的承运方案,需要生产不同规格的卡车、轮船

    #include 
    using namespace std;
    
    class Vehicles
    {
    public:
        virtual void Show() = 0;
    };
    //陆运    
    class Truck : public Vehicles
    {
    public:
        void Show() { cout << "This is a truck" << endl; }
    };
    //海运    
    class Ship : public Vehicles
    {
    public:
        void Show() { cout << "This is a ship" << endl; }
    };
    //大型载具    
    class BigVehicles
    {
    public:
        virtual void Show() = 0;
    };
    class BigTruck : public BigVehicles
    {
    public:
        void Show() { cout << "This is a BIG truck" << endl; }
    
    };
    class BigShip : public BigVehicles
    {
    public:
        void Show() { cout << "This is a BIG ship" << endl; }
    };
    //工厂    
    class Factory
    {
    public:
        virtual Vehicles* CreateVehicles() = 0;
        virtual BigVehicles* CreateBigVehicles() = 0;
    };
    //卡车工厂,生产大型、小型卡车
    class FactoryTruck :public Factory
    {
    public:
        Vehicles* CreateVehicles() { return new Truck(); }
        BigVehicles* CreateBigVehicles() { return new BigTruck(); }
    };
    //船工厂,生产大型、小型船
    class FactoryShip : public Factory
    {
    public:
        Vehicles* CreateVehicles() { return new Ship(); }
        BigVehicles* CreateBigVehicles() { return new BigShip(); }
    };
    
    int main()
    {
        FactoryTruck* m_TruckFactory = new FactoryTruck();
        FactoryShip* m_ShipFactory = new FactoryShip();
    
        Vehicles* m_Truck = m_TruckFactory->CreateVehicles();
        Vehicles* m_Ship = m_ShipFactory->CreateVehicles();
    
        BigVehicles* m_BigTruck = m_TruckFactory->CreateBigVehicles();
        BigVehicles* m_BigShip = m_ShipFactory->CreateBigVehicles();
    
        m_Ship->Show();
        m_Truck->Show();
        m_BigShip->Show();
        m_BigTruck->Show();
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 如果需要拓展抽象工厂里面的方法会比较麻烦,因为我们必须修改抽象类以及添加对应的产品,这样修改量比较大,但是每种产品之间相互解耦。

    1. 建造者模式
    • 模式意图
      将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    特点: 用于对复杂对象的构造、初始化,与工厂模式不同的是,建造者的目的在于把复杂构造过程从不同对象展现中抽离出来,使得同样的构造工序可以展现出不同的产品对象。

    • 适用场景

    • 相同的方法,不同的执行顺序,产生不同的结果时,可以采用建造者模式。

    • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。

    • 产品类非常复杂,或者产品类中的方法调用顺序不同产生了不同的效能,这个时候使用建造者模式。

    都builder了,就举一个盖房子的例子
    比如盖一栋房子需要 地基 墙体 房顶三部分组成

    我们创建建筑物类Building
    抽象出建造方法类Builder
    创建一个HouseBuilder用来描述具体各部件的构造方式
    最后用Director类对构造流程进行管理,通过它选择不同的构造方式,并明确具体的构造流程,最终得到我们的复杂产品

    #include 
    #include 
    using namespace std;
    
    class Building
    {
    private:
    	vector BuildingComponents;
    public:
    	void SetBasement(string basement) {
    		BuildingComponents.push_back(basement);
    	}
    	void SetWall(string wall) {
    		BuildingComponents.push_back(wall);
    	}
    	void SetRoof(string roof) {
    		BuildingComponents.push_back(roof);
    	}
    
    	void PrintBuilding() {
    		for (int i = BuildingComponents.size() - 1; i >= 0; i--) {
    			cout << BuildingComponents[i] << endl;
    		}
    		return;
    	}
    };
    
    class Builder
    {
    public:
    	virtual void BuildBasement() = 0;
    	virtual void BuildWall() = 0;
    	virtual void BuildRoof() = 0;
    	virtual void GetBuilding() = 0;
    };
    
    class HouseBuilder : public Builder
    {
    private:
    	Building house;
    
    public:
    	void BuildBasement() {
    		house.SetBasement("这里是house地基");
    	}
    	void BuildWall() {
    		house.SetWall("这里是house墙壁");
    	}
    	void BuildRoof() {
    		house.SetRoof("  house房顶!  ");
    	}
    	void GetBuilding() {
    		house.PrintBuilding();
    	}
    };
    
    class Director
    {
    private:
    	Builder* m_pBuilder;
    public:
    	Director(Builder* builder) { m_pBuilder = builder; }
    	void Create() {
    		m_pBuilder->BuildBasement();
    		m_pBuilder->BuildWall();
    		m_pBuilder->BuildWall();
    		m_pBuilder->BuildWall();
    		m_pBuilder->BuildWall();
    		m_pBuilder->BuildRoof();
    		m_pBuilder->GetBuilding();
    	}
    };
    
    int main()
    {
    	HouseBuilder ahouse;
    	Director director(&ahouse);
    	director.Create();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    1. 原型模式
    • 模式意图
      用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象

    特点:

    • 性能较好,原型模式是内存二进制流的复制,会比直接new一个对象性能较好
    • 因为是直接复制,所以绕开了构造函数,这是优点也是缺点,要看实际使用场景
    #include 
    using namespace std;
    //具体的实现类
    class Sheep
    {
    public:
        Sheep(int id, string name) :m_id(id), m_name(name)
        {
    
            cout << "new Sheep Comes" << endl;
        }
    
        //关键代码拷贝构造函数
        Sheep(const Sheep& obj)
        {
            this->m_id = obj.m_id;
            this->m_name = obj.m_name;
        }
        //关键代码克隆函数,返回return new Sheep(*this)
        Sheep* clone()
        {
            return new Sheep(*this);
        }
        void show()
        {
            cout << "id  :" << m_id << endl;
            cout << "name:" << m_name.data() << endl;
            cout << "Sheep id address:" << &m_id << endl;
            cout << "Sheep name address:" << &m_name << endl;
        }
    private:
        int m_id;
        string m_name;
    };
    int main()
    {
        Sheep* s1 = new Sheep(9, "肖恩");
        s1->show();
        Sheep* s2 = s1->clone();
        s2->show();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    一、高频题集
    [wp][RCTF2015]EasySQL
    短视频短剧小程序系统:创新的内容传播与互动体验
    二叉树 | 递归遍历 | leecode刷题笔记
    matlab simulink响应谱计算
    用哈希简单封装unordered_map和unordered_set
    跨境电商的推广方式有哪些
    如何设计日志内容
    【Node】cookie、sessionStorage、localStorage 与 身份认证
    网络名词介绍
  • 原文地址:https://blog.csdn.net/qq_41943808/article/details/126495815