设计模式C++工厂方法

设计模式C++工厂方法

注:参考视频:【设计模式(完整版)】https://www.bilibili.com/video/BV1Zd4y1t7HK?p=3&vd_source=eee55dc084ebc7a8d4f5db673a3c06f9

分类:(类)创建型

这个工厂方法就是一个像工厂一样的方法,而方法则是类的成员函数.

就像养宠物一样,我们不希望让宠物到处乱跑,哪里都是它,把它关起来,限制活动区域到一定的大小.我们这里学习的就是具体怎么做.

原则:把new关起来,实现创造者和产品松耦合(把创建的过程延迟到对象)

问题:一个物流公司最初只使用卡车运输,现需要增加轮船运输业务.目前的程序代码只与卡车关联.(需要改变现有代码,同时考虑增加以后的别的业务)

初始代码

#include <iostream>

class Truck
{
public:
    void deliver()
    {
        std::cout<<"卡车运输货物ing..."<<std::endl;
    }
};
​
class Logistics
{
public:
    void doSomething(){
        Truck *truck = new Truck();
        truck->deliver();
        delete truck;
}
};
int main()
{
    Logistics* logistics = new Logistics();
    logistics->doSomething();
}

由上面代码可以知道我们如果加轮船运输的话很简单,只需要创建一个Ship类,Ship类中实现与卡车类相同.

加入Ship类后

#include <iostream>
class Truck
{
public:
    void deliver()  
    {   
        std::cout<<"卡车运输货物ing..."<<std::endl;   
    }
};
​
// 新加类
class Ship 
{
public:
    void deliver()  
    {
        std::cout<<"轮船运输货物ing..."<<std::endl;   
    }
};
class Logistics
{
public:
    void doSomething(){ 
        Truck *truck = new Truck();
        truck->deliver();
        delete truck;
}
};
int main()
{
    Logistics* logistics = new Logistics();
    logistics->doSomething();
}
 

问题来了,当我们添加轮船类之后,我们要怎么使用这个轮船类呢?Logistics类怎么改?

问题来了之后解决方法有很多,我们这里使用的是继承,依照以下图进行修改.

就像是总公司下两个子公司一样,我们一个子公司使用卡车运输,一个子公司使用轮船运输,所以创造一个子公司,主要使用继承方面的知识

注:以下代码阅读顺序建议从类TruckLogistics作为切入口开始看

#include <iostream>
​
//新加基类,派生类为Truck,Ship
class Transport
{
public:
    virtual ~Transport(){}
    //纯虚函数,当做一个接口
    //在派生类中并没有改变里面的成员,所以习惯我们会加上const修饰,虚函数基类加上const修饰后,派生类的方法也需要加上const修饰
    // Logistics类中加const原因相同
    virtual void deliver()  const = 0;
​
};
​
class Truck : public Transport 
{
public:
    void deliver() const override  // override关键字说明你这个方法是继承过来的,
                                // 当你拼错时,编译器在基类找不到虚函数,不会认为是一个新的成员函数而是会直接报错提醒你
    {
        std::cout<<"卡车运输货物ing..."<<std::endl;
    }
};
​
class Ship : public transport
{
public:
    void deliver() const override
    {
        std::cout<<"轮船运输货物ing..."<<std::endl;
    }
​
};
​
class Logistics
{
public:
    //新加代码,
   //作为一个好的习惯,在有继承关系的基类和派生类中,我们一般都会写一个虚的析构函数.在本例中没有用,但是作为一个习惯加入比较好
    virtual ~Logistics(){}
    //新加代码
    virtual Transport * factoryMethod() const = 0;
    void doSomething() const {
        //修改前(注释部分)
        //Truck *truck = new Truck();
        //truck->deliver();
        //delete truck;
        
        //修改后
        Transport * transport = factoryMethod();
        transport->deliver();
    
        delete transport;
        //此时先看等式左边,我们需要一个Transport类作为Truck和Ship的基类.由此往上转至Transport类,看完之后返回顺着看等式右边
        //等式右边就是延迟new的方法,使用纯虚函数来让继承的派生类TruckLogistics,ShipLogistics来new,下转至这两个派生类
}
};
//新加类
class TruckLogistics : public Logistics
{
public:
    virtual ~TruckLogistics(){}
    //在传统编程中,我们一般都是自上而下,所以一般来说为我们都会把基类中的doSomething方法写到派生类中,
    //在此例子中我们学习的是设计模式中的工厂方法,是使用类的方式是延时new,我们真正要改变的是doSomething方法中Truck *truck = new Truck()
    //我们希望泛泛一点,面向接口编程,所以下一步修改doSomething方法
    vitrual Transport* factoryMethod() const override{
        return new Truck(); 
}
};
​
//新加类
class ShipLogistics : public Logistics
{
public:
    virtual ~ShipLogistics(){}
    virtual Transport* factoryMethod() const override{
        return new Ship();      
​
};
    
int main()
{
    //修改前代码
    //因为基类有虚函数,实现功能不完整,所以我们这里new直接new派生类
    //Logistics* logistics = new Logistics();
    //logistics->doSomething();
    Logistics* truckLogistics = new TruckLogistics();
    truckLogistics->doSomething();
    truckLogistics->doSomething();
    truckLogistics->doSomething();
    
    //我们现在添加轮船类的代码也是很简单,业务拓展
    Logistics* shipLogistics = new ShipLogistics();
    shipLogistics->doSomething();
    shipLogistics->doSomething();
    shipLogistics->doSomething();
    
    delete truckLogistics;
    delete shipLogistics;   
​
}

解决方案:定义一个用于创建对象的接口,让子类决定实例化哪一个类.factoryMethod使一个类的实例化延迟到其子类.

设计模式使用的过程往往就是一个重构的过程 设计原则 : 依赖倒置

传统编程中: 我们需要一个物流业务() 物流业务拓展之后就有两个子业务() 子业务需要用到传输方式,就会依赖底层的传输方式 (这里上层指的是业务,下层指的是传输方式

依赖倒置: 因为我们有两种产品(运输方式) 中间加一层,抽象出来一种接口(传输方式/产品) 重点是不仅是这两种传输方式依赖于这个接口 上层的业务也依赖于这个接口0

依赖倒置就是依赖抽象而不是依赖现有的类 与针对接口编程而不要针对实现编程相比,依赖倒置更加注重抽象的概念 产品与创造者都要依赖抽象 倒置则是从具体的产品往上依赖

工厂方法优缺点:

优点:

对拓展开放,对修改关闭

依赖倒置

单一职责原则

缺点:

应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂.最好的情况是将该模式引入创建者类的现有层次结构中.

可以运行的有一些注释的完整代码:

#include <iostream>
​
class Transport { // product接口 对接口进行声明
public:
    virtual ~Transport(){}
    virtual void deliver() const = 0;
​
};
class Truck: public Transport //ConcreteProduct A  接口的具体实现
{
public:
    void deliver() const override 
    {
        std::cout << "卡车运输货物中ing..." << std::endl;
    }
};
class Ship:public Transport //ConcreteProduct B   接口的具体实现
{
public:
    void deliver() const override 
    {
        std::cout << "轮船运输货物中ing..." << std::endl;
    }
};
class Logistics //creator  声明返回产品对象的工厂方法
{
public:
    virtual Transport *factoryMethod() const = 0; // 工厂方法
    void doSomething() const { // 一些业务
        //优化:Truck * truck = new Truck();
​
        Transport* transport = factoryMethod();
        transport->deliver();
        delete transport;
    }
    virtual ~Logistics(){}
​
};
​
class TruckLogistics : public Logistics{ //ConcreteCreator A  重写基础工厂方法,使其返回不同类型的产品
public:
    virtual ~TruckLogistics(){}
    virtual Transport* factoryMethod() const override 
    {
        //把new关在笼子里
        return new Truck;
    }
};
class ShipLogistics : public Logistics { //ConcreteCreator B  重写基础工厂方法,使其返回不同类型的产品
public:
    virtual ~ShipLogistics() {}
    virtual Transport* factoryMethod() const override
    {
        //把new关在笼子里
        return new Ship;
    }
};
int main()
{
    //Logistics* logistics = new Logistics();
    Logistics* truckLogistics = new TruckLogistics();
    Logistics* shipLogistics = new ShipLogistics();
​
    truckLogistics->doSomething();
    truckLogistics->doSomething();
    truckLogistics->doSomething();
    
    shipLogistics->doSomething();
    shipLogistics->doSomething();
    shipLogistics->doSomething();
    
    delete truckLogistics;
    delete shipLogistics;
​
}

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值