设计模式-工厂模式 C++

一、简介

工厂模式属于一种创建型模式,它提供一种创建对象的最佳方式,对外不暴露对象的创建,并且通过一个共同的接口获取对象指针。

就像一个工厂根据消费者的需求生产不同的产品,但是并不需要对消费者开放生产方式。消费者只需要使用产品就好,并不需要知晓产品的生成。

适用场景:一般需要生成复杂对象的时候使用工厂模式。但是如果是比较简单的对象,则最好不要使用工厂模式,因为工厂模式需要创建工厂类,增加了系统的复杂性。

二、简单工厂模式

简单工厂模式,封装工厂类,用来提供创建目标对象的方法。

以服装厂为例。假设服装厂可以生产T恤和裤子两种产品。

1、先创建一个衣服的抽象类

//衣服抽象类
class Clothe
{
public:
	virtual void Show() = 0;
	virtual ~Clothe() {}
};

2、然后,我们创建具体的产品:T恤产品和裤子产品。此类继承于Clothe

//T恤衫产品具体类
class TShirt : public Clothe
{
public:
	void Show()
	{
		cout << "This is T-shirt!" << endl;
	}
};

//裤子产品具体类
class Pants : public Clothe
{
public:
	void Show()
	{
		cout << "This is Pants!" << endl;
	}
};

3、创建工厂,此工厂会根据“客户”的需求,生产对应的产品(即实例化相应的对象)

typedef enum
{
	T_SHIRT,
	PANTS
}CLOTHE_TYPE;

//服装工厂
class ClotheFactory
{
public:
    Clothe* CreateClothe(CLOTHE_TYPE myType)
    {
        switch (myType)
        {
            case CLOTHE_TYPE::T_SHIRT:
                return new TShirt();

            case CLOTHE_TYPE::PANTS:
                return new Pants();

            default:
                return nullptr;
        }

        return nullptr;
    }

    virtual ~ClotheFactory() {}
};

4、最后,我们可以调用这个工厂生产产品了。

需要注意的是,因为clothe其实是new出来的,使用完后需要delete释放掉。

int main()
{
    //调用工厂生产裤子
    ClotheFactory factory;
    Clothe* clothe = factory.CreateClothe(CLOTHE_TYPE::PANTS);
    clothe->Show();

    //new的对象使用完后需要delete
    delete clothe;
    clothe = nullptr;

    system("pause");
    return 0;
}

从简单工厂模式的描述,我们可以看到工厂直接提供了实例化“产品”的方法,即CreateClothe,虽然保护了对象实例化的过程,但是不符合面向对象编程的开闭原则。

开闭原则:在面向对象领域,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”。

假如工厂还需要再增加产品,对于简单工厂模式来说,就需要修改CreateClothe的实现,这违背了开闭原则。所以我们可以使用下面的工厂方法模式来解决这个问题。

三、工厂方法模式

使用抽象类接管工厂的管理,额外定义各个产品单独实现的具体工厂,这些工厂继承了抽象工厂,用来实现具体对象的创建。

以服装厂为例,可以把抽象类理解为一家服装厂公司,这家公司旗下目前有2家工厂,一间只生产T恤,一间只生产裤子。如果有新类型的产品裙子需要增加,就再增加一间工厂,只用来生产裙子,这样就不用改变原来2个工厂的生产内容了,符合开闭原则。

具体代码示例

1、先创建一个衣服的抽象类,此类并不会具体“生产”产品,代码同简单工厂模式

2、然后,我们创建具体的产品:T恤产品和裤子产品,代码同简单工厂模式

3、创建一个抽象类,作为“服装厂公司”,此类作为接口,不再具体实例化产品

//服装工厂
class ClotheFactory
{
public:
    virtual Clothe* CreateClothe() = 0;
};

4、定义生产各个产品的工厂

//T恤工厂,只用来生产T恤
class TShirtFactory : public ClotheFactory
{
public:
    virtual Clothe* CreateClothe()
    {
        return new TShirt();
    }
};

//裤子工厂,只用来生产裤子
class PantsFactory : public ClotheFactory
{
public:
    virtual Clothe* CreateClothe()
    {
        return new Pants();
    }
};

5、可以开始生产了

int main()
{
    //调用工厂生产T恤
    ClotheFactory* factory = new TShirtFactory();

    if (nullptr != factory)
    {
        Clothe* clothe = factory->CreateClothe();

        if (nullptr != clothe)
        {
            clothe->Show();

            //new的对象使用完后需要delete
            delete clothe;
            clothe = nullptr;
        }
    }

    system("pause");
    return 0;
}

【注】如果这家工厂公司需要增加产品裙子,则再增加一个生产裙子的工厂就可以。即再增加如下代码即可

//裙子产品
class Skirt : public Clothe
{
public:
    void Show()
    {
        cout << "This is Skirt!" << endl;
    }
};

//裙子工厂,只用来生产裙子
class SkirtFactory : public ClotheFactory
{
public:
	virtual Clothe* CreateClothe()
	{
		return new Skirt();
	}
};

可见,工厂方法模式对于简单方法模式来说,增加了系统的复杂度。因为每增加一个产品都要新增一个具体工厂类。对于我们日常写项目来说,需要根据具体情况做取舍。

工厂方法模式还存在一个问题,我们根据抽象工厂ClotheFactory只能去实例化一种类型的产品,即可以实例化继承于Clothe类的TShirt和Pants。而无法创建其他类型(即继承于其他抽象产品类的)对象。

比如,由于疫情来袭,这家服装厂公司决定开辟一条口罩的生产线,用于生产例如N95口罩、医用外科口罩等。由此我们要定义

A、一个口罩抽象产品类

//口罩抽象类
class Mask
{
public:
    virtual void equip() = 0;
    virtual ~Mask() {};
};

B、N95口罩和外科口罩具体类

//N95口罩具体类
class N95Mask : public Mask
{
    virtual void equip()
    {
        cout << "equipped N95 mask!" << endl;
    }
};

//外科口罩具体类
class SurgicalMask : public Mask
{
    virtual void equip()
    {
        cout << "equipped surgical mask!" << endl;
    }
};

但是在创建工厂的时候,我们犯了难,现有工厂是无法扩展出对口罩的生产创建的。现有的工厂抽象类ClotheFactory中没有对Mask类的创建方法,所以无论如何,我们都需要在工厂抽象类中修改出对Mask产品的创建方法,即我们需要违背开闭原则,使用下面介绍的抽象工厂模式来解决这个问题。

四、抽象工厂模式

抽象工厂模式适用于需要管理不同类型的类对象的实例化的情况。是工厂方法模式的扩展。抽象工厂模式不符合开闭原则。

以上诉问题例,如果这家工厂打算扩展口罩的生产业务。则需要

1、创建口罩产品抽象类,代码见上诉A

2、创建具体口罩产品的具体实现类,代码见上诉B

3、修改工厂抽象类,此类需要增加生成Mask的方法CreateMask,所以再使用ClotheFactory作为类名不是很合适,改成Factory

//工厂抽象类
class Factory
{
public:
    virtual Clothe* CreateClothe(CLOTHE_TYPE type) = 0;
    virtual Mask* CreateMask(MASK_TYPE type) = 0;
};

4、生产工厂具体类,具体实现根据传入参数生成对应的clothe或mask

//生产工厂具体类
class ProduceFactory : public Factory
{
public:
    virtual Clothe* CreateClothe(CLOTHE_TYPE type)
    {
        switch (type)
        {
            case CLOTHE_TYPE::T_SHIRT:
                return new TShirt();

            case CLOTHE_TYPE::PANTS:
                return new Pants();

            default:
                return nullptr;
        }

        return nullptr;
    }

    virtual Mask* CreateMask(MASK_TYPE type)
    {
        switch (type)
        {
            case MASK_TYPE::N95_MASK:
                return new N95Mask();

            case MASK_TYPE::SURGICAL_MASK:
                return new SurgicalMask();

            default:
                return nullptr;
        }

        return nullptr;
    }
};

5、然后,就可以调用生产了

int main()
{
    //调用工厂生产T恤
    Factory* factory = new ProduceFactory();

    if (nullptr != factory)
    {
        //生产T恤
        Clothe* clothe = factory->CreateClothe(CLOTHE_TYPE::T_SHIRT);

        if (nullptr != clothe)
        {
            clothe->Show();

            //new的对象使用完后需要delete
            delete clothe;
            clothe = nullptr;
        }

        //生产医用外科口罩
        Mask* mask = factory->CreateMask(MASK_TYPE::SURGICAL_MASK);

        if (nullptr != mask)
        {
            mask->equip();

            delete mask;
            mask = nullptr;
        }
    }

    system("pause");
    return 0;
}

从上面的逻辑可以看出,如果工厂需要新增生产另一类产品,则必须要对抽象工厂类以及具体实现Create的工厂类进行修改,所以是不符合开闭原则的。

参考&致谢

C++ 深入浅出工厂模式(初识篇) - 知乎初识工厂模式我们先看工厂模式的介绍 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建…https://zhuanlan.zhihu.com/p/83535678

五分钟学设计模式.04.抽象工厂模式_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1y54y1B7k6?spm_id_from=0.0.header_right.history_list.click

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值