常用设计模式之 - 工厂设计模式(简单工厂、工厂方法、抽象工厂)

版权声明:QQ:763905926 未经允许请勿转载,转载请注明出处! https://blog.csdn.net/lms1008611/article/details/89598586

    工厂模式是最常用的创建型模式之一,在开始工厂模式之前,我们先来看一个场景,假如要设计一个电脑类,生成的电脑对象要包含CPU,那么可能有人会这么设计:

class PC
{
private:
    string m_CPU;
public:
    PC(string nPCName)
    {
        if("Apple" == nPCName)
        {
            m_CPU = "Apple_CPU";
        }
        else if("Dell" == nPCName)
        {
            m_CPU = "Dell_CPU";
        }
    }

    string getCPU()
    {
        return m_CPU;
    }
};

这里举的例子中假设苹果电脑用自己CPU,戴尔电脑用自己的CPU(当然也可能是第三方的CPU),然后按照下边的方式使用

int main(int argc, char* argv[])
{
    PC ApplePC("Apple");
    cout << ApplePC.getCPU() << endl;

    return 0;
}

可以得到输出的CPU是苹果的,但是这里个问题是,假如有一天要生成HP电脑,那么我们就必须要改PC类,在里边增加else if("HP" == nPCName){HP电脑初始化},这就导致了每增加一个电脑品牌,都要在PC类中做修改,这违背了设计模式中的开闭原则。

      为了解决上面的问题,我们引出标题中的简单工厂模式,在简单工厂模式中,我们要引入三个角色:
      1、Factory(工厂角色):工厂角色是简单工厂模式的核心,负责创建所有产品实例,返回的是抽象产品类型(见第2点)
      2、Product(抽象产品角色):作为所有产品类的父类封装了产品类的共有方法。
      3、ConcreteProduct(具体产品角色):继承自抽象产品角色而创建的实实在在的目标,并实现了抽象产品角色中的共有方法。

有了以上三点,我们来改造下我们的代码:
首先创建一个电脑的产品类(包括PC抽象类、PC具体类),抽象类中接口为获取CPU的纯虚函数

//PC的抽想产品类
class PC
{
public:
    virtual string getCPU() = 0;
};

//具体PC类:Apple电脑,继承自PC抽象类
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具体PC类:Dell电脑,继承自PC抽象类
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

接着来创建简单工厂的核心部分:工厂类(要点为返回的值为抽象产品类,才能实现多态)

class PCFactory
{
public:
    //这里设为静态函数的目的是可以直接通过类名::createPC调用,不需要实例化工厂对象
    //需要注意的是:返回值为产品的抽象类(这里为电脑抽象类PC)
    static PC* createPC(string nPCName)
    {
        if("Apple" == nPCName)
        {
            return new ApplePC;
        }
        else if("Dell" == nPCName)
        {
            return new DellPC;
        }
    }
};

到这里,我们的简单工厂模式已经设计完成,使用如下:

int main(int argc, char* argv[])
{
    PC* pPC = PCFactory::createPC("Apple");

    cout << pPC->getCPU() << endl;

    return 0;
}

简单工厂模式在一定程度上解决了问题, 但是细心的朋友会发现,当我们需要增加HP电脑时,就需要更改PCFactory工厂类中的方法,也就是说每次更改增加一个电脑,就要重新编译客户端的工厂类。

导致 这个问题的原因就是:简单工厂模式所有的产品都由同一个工厂生产,那有没有可能是设置一个只负责下命名的总工厂,而生产产品的工作由各个子工厂完成,答案是肯定的,这就是即将要说的工厂模式。其实这 跟企业的管理模式有异曲同工之妙,总部只负责下达命令我要生产什么,具体生产执行则由各个工厂去完成。

    现在来看看工厂模式需要的几个要素
       1、Factory(抽象工厂角色):抽象工厂角色是工厂模式的核心,声明公共的创建方法(即指令),具体工厂要继承抽象工厂并实现接口。
       2、ConcreteFactory(具体工厂角色):继承抽象工厂,实现创建接口创建具体的产品
       3、Product(抽象产品角色):作为所有产品类的父类封装了产品类的共有方法。
       4、ConcreteProduct(具体产品角色):继承自抽象产品角色而创建的实实在在的目标,并实现了抽象产品角色中的共有方法。

//抽象产品(电脑)
class PC
{
public:
    virtual string getCPU() = 0;
};

//具体产品(Apple电脑)
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具体产品(Dell电脑)
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

//抽象工厂(工厂总部)
class Factory
{
public:
    virtual PC* createPC() = 0;
};

//具体工厂(Apple工厂)
class AppleFactory : public Factory
{
public:
    PC* createPC()
    {
        return new ApplePC;
    }
};

//具体工厂(Dell工厂)
class DellFactory : public Factory
{
public:
    PC* createPC()
    {
        return new DellPC;
    }
};


int main(int argc, char* argv[])
{
    Factory* f = new DellFactory; //下达指令到Dell工厂(要生产Dell电脑)
    PC* pPC = f->createPC();      //Dell工厂生产电脑

    cout << pPC->getCPU() << endl; //使用具体的产品

    return 0;
}

到这,工厂模式就结束了,但是需求会回来越多,假如我要使用电脑、手机两个设备连成一个家庭套餐使用。那就有可能不同品牌间的手机电脑无法正常连接或者使用体验不好。比方我们用的电脑时Apple的,但是手机是HW,那么他们的使用体验可能就不那么友善了。


    为了解决这个问题,我们引出了工厂模式中的最后一种:抽象工厂
    抽象工厂解决的问题属于创建一个产品族,举个例子就是工厂里生产苹果电脑、苹果手机、苹果手环等等,生产出来的家族产品可以很吻合的配合使用。(这里应该把抽象工厂定义成家族工厂是不是更合适些?嘿嘿嘿...)

    有了以上工厂模式的基础,抽象工厂就很简单了,现在工厂只生产电脑,那么我们直接把手机产品线也放进去好了,得到的结果就是生产出来的要么是ApplePC+iPhone,要么是DellPC+DPhnoe(额。。自己开创品牌),抬椅子上马:

//抽象产品(电脑)
class PC
{
public:
    virtual string getCPU() = 0;
};

//具体产品(Apple电脑)
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具体产品(Dell电脑)
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

//抽象产品(手机)
class Phone
{
public:
    virtual string call() = 0;
};

//具体产品(iPhone)
class iPhone : public Phone
{
public:
    string call()
    {
        return "iPhone du...du...";
    }
};

//具体产品(DPhone)
class DPhone : public Phone
{
public:
    string call()
    {
        return "DPhone du...du...";
    }
};

//抽象工厂(工厂总部)
class Factory
{
public:
    virtual PC* createPC() = 0;
    virtual Phone* createPhone() = 0;
};

//具体工厂(Apple工厂)
class AppleFactory : public Factory
{
public:
    PC* createPC()
    {
        return new ApplePC;
    }
    Phone* createPhone()
    {
        return new iPhone;
    }
};

//具体工厂(Dell工厂)
class DellFactory : public Factory
{
public:
    PC* createPC()
    {
        return new DellPC;
    }
    Phone* createPhone() 
    {
        return new DPhone;
    }
};

int main(int argc, char* argv[])
{
    Factory* f = new AppleFactory; //下达指令到Apple工厂(要生产Apple系列产品)
    PC* pPC = f->createPC();      //Apple工厂生产Apple mac
    Phone* pPhone = f->createPhone(); //Apple工厂生产iPhone

    cout << pPC->getCPU() << endl; //使用Apple Mac
    cout << pPhone->call() << endl;//使用iPhone

    return 0;
}

到此,工厂模式的三种类型都讲完了。

猜你喜欢

转载自blog.csdn.net/lms1008611/article/details/89598586