笔记十三:设计模式之简单工厂模式、工厂方法模式、抽象工厂模式

引言:
假设现在有一个超市(Market),超市销售饼干(Biscuit)、水果(Fruit)、饮料(Drink)三种食品。
这里写图片描述
按照常规,我们建立三个类:class Biscuit、class Fruit、class Drink。

class Biscuit{
public:
    Biscuit(){}
    ~Biscuit(){}
    void Show(){ cout << "Hi,customers! I'm Biscuit!" << endl; }
};

class Fruit{
public:
    Fruit(){}
    ~Fruit(){}
    void Show(){ cout << "Hi,customers! I'm Fruit!" << endl; }
};

class Drink{
public:
    Drink(){}
    ~Drink(){}
    void Show(){ cout << "Hi,customers! I'm Drink!" << endl; }
};

现在假设我们有饼干2件、水果2件、饮料2件。则:

Biscuit* pBiscuit1 = new Biscuit();
pBiscuit1->Show();
Biscuit* pBiscuit2 = new Biscuit();
pBiscuit2->Show();

Fruit* pFruit1 = new Fruit();
pFruit1->Show();
Fruit* pFruit2 = new Fruit();
pFruit2->Show();

Drink* pDrink1 = new Drink();
pDrink1->Show();
Drink* pDrink2 = new Drink();
pDrink2->Show();

这里写图片描述

1、从上述代码中,我们发现:1)每一个具体的食品的创建都暴露在用户面前2)假设每一类食品的数目增多,若100个,那么代码中得new 100*3次,代码冗余量变大。

2、当用户不需要了解到具体食品的创建细节,而只需要知道它是什么,同时又能减少代码冗余,有没有什么好的办法呢?


简单工厂模式

文章前面讲饼干、水果、饮料进行单独构造类,三者之间没有任何关联。为了对它们进行封装,可以根据它们之间的某种联系构造成一个整体,这样细节之处,就被封装在这个整体之中,而用户无法得知(也不需要知道)。由于三种商品属性均为食品,因此, 基类与派生类的概念被引入,这样,三种食品就有了关联。同时,“超市”这一概念有什么用呢?我们可以把食品类构造的细节操作放在超市类中,这样就完成了 封装

这里写图片描述

这里将简单工厂模式的结构与超市-饼干-水果-饮料对象进行映射。具体代码如下:

/************************************
 * Function:    简单工厂模式案例
 * @Copyright:
 * Author:      by sun
 * Date:        2016-07-13
************************************/

//商品名
typedef enum ProductTag
{
    BiscuitTag,
    FruitTag,
    DrinkTag
} PRODUCTTAG;

//食品基类
class Product{
public:
    Product(){}
    ~Product(){}
    virtual void Show(){ cout << "Hi, customers! I'm Product!" << endl; }
};

//饼干
class Biscuit :public Product
{
public:
    Biscuit(){}
    ~Biscuit(){}
    void Show(){ cout << "Hi,customers! I'm Biscuit!" << endl; }
};

//水果
class Fruit :public Product
{
public:
    Fruit(){}
    ~Fruit(){}
    void Show(){ cout << "Hi,customers! I'm Fruit!" << endl; }
};

//饮料
class Drink :public Product
{
public:
    Drink(){}
    ~Drink(){}
    void Show(){ cout << "Hi,customers! I'm Drink!" << endl; }
};

//超市
class Market{
public:
    Market(){}
    ~Market(){}
    Product* SellProduct(PRODUCTTAG ItemTag) const;
};

Product* Market::SellProduct(PRODUCTTAG ItemTag) const
{
    switch (ItemTag)
    {
    case BiscuitTag:
        return new Biscuit();
        break;
    case FruitTag:
        return new Fruit();
    case DrinkTag:
        return new Drink();
        break;
    }
};
Market* pMarket = new Market();
Product* pBiscuit = pMarket->SellProduct(BiscuitTag);
pBiscuit->Show();
Product* pFruit = pMarket->SellProduct(FruitTag);
pFruit->Show();
Product* pDrink = pMarket->SellProduct(DrinkTag);
pDrink->Show();

Product* pBiscuit1 = pMarket->SellProduct(BiscuitTag);
pBiscuit1->Show();
Product* pFruit1 = pMarket->SellProduct(FruitTag);
pFruit1->Show();
Product* pDrink1 = pMarket->SellProduct(DrinkTag);
pDrink1->Show();

1、可以看出,关于饼干、饮料、水果的具体的构造操作(new)不再直接暴露在用户面前,而是封装在Market类中,第一个目的已经完成。

2、同样是每件商品均产生2个,代码中出现的new的个数仍旧只有3个,当每种食品为100个的时候,尽管实际调用了100*3次new,但写在代码中的new也还是只有3个,减少了代码冗余,完成了第2个目标。

现在,当食品种类增加,比如出现了坚果(nut)、面包(bread),那么如何修改上述代码呢?
第一:枚举类型扩充

//商品名
typedef enum ProductTag
{
    BiscuitTag,
    FruitTag,
    DrinkTag,
    NutTag,
    BreadTag
} PRODUCTTAG;

第二:以Product作为基类的派生类增加

//坚果
class Nut :public Product
{
public:
    Nut(){}
    ~Nut(){}
    void Show(){ cout << "Hi,customers! I'm Nut!" << endl; }
};

//面包
class Bread :public Product
{
public:
    Bread(){}
    ~Bread(){}
    void Show(){ cout << "Hi,customers! I'm Bread!" << endl; }
};

第三:Market类修改

switch (ItemTag)
    {
    case BiscuitTag:
        return new Biscuit();
        break;
    case FruitTag:
        return new Fruit();
    case DrinkTag:
        return new Drink();
        break;
    case NutTag:
        return new Nut();
        break;
    case BreadTag:
        return new Bread();
        break;
    }
Market* pMarket = new Market();
    Product* pBiscuit = pMarket->SellProduct(BiscuitTag);
    pBiscuit->Show();
    Product* pFruit = pMarket->SellProduct(FruitTag);
    pFruit->Show();
    Product* pDrink = pMarket->SellProduct(DrinkTag);
    pDrink->Show();

    Product* pNut = pMarket->SellProduct(NutTag);
    pNut->Show();
    Product* pBread = pMarket->SellProduct(BreadTag);
    pBread->Show();

这里写图片描述

这里我们发现,当增加食品种类时,Market类中switch函数需要修改,若增加的Nut和Bread操作不当,则会影响已经建立的Biscuit、Fruit、Drink。且,测试的时候,由于switch代码被修改,则其整个功能需全部重新测试,重复已完成工作量。——这就是通常意义上说的违反了开闭原则。

简单工厂模式:

优点:封装了对象的接口,减少代码冗余
缺点:耦合度较高,扩展性不好


工厂方法模式

在简单工厂模式的基础上,为了减少耦合度,提高代码的扩展性,对“工厂类”添加了一个抽象类,将工厂共同的动作抽象出来。而具体的行为由子类本身去实现,让子类决定生产什么样的产品。

这里写图片描述

FactoryA、FactoryB、FactoryC是新增的Factory的子类,每个子类分管自己的辖区。

/****************************************
 * Function:    工厂方法模式模式案例
 * @Copyright: 
 * Author:      by sun
 * Date:        2016-07-13
 ***************************************/


//食品基类
class Product{
public:
    Product(){}
    ~Product(){}
    virtual void Show(){ cout << "Hi, customers! I'm Product!" << endl; }
};


//饼干
class Biscuit :public Product
{
public:
    Biscuit(){}
    ~Biscuit(){}
    void Show(){ cout << "Hi,customers! I'm Biscuit!" << endl; }
};

//水果
class Fruit :public Product
{
public:
    Fruit(){}
    ~Fruit(){}
    void Show(){ cout << "Hi,customers! I'm Fruit!" << endl; }
};

//饮料
class Drink :public Product
{
public:
    Drink(){}
    ~Drink(){}
    void Show(){ cout << "Hi,customers! I'm Drink!" << endl; }
};

//超市
class Market{
public:
    Market(){};
    ~Market(){};
    virtual Product* SellProduct() { return new Product(); }

};

//饼干区
class BiscuitArea:public Market
{
public:
    BiscuitArea(){};
    ~BiscuitArea(){};
    Product* SellProduct(){ return new Biscuit(); }
};

//水果区
class FruitArea :public Market
{
public:
    FruitArea(){};
    ~FruitArea(){};
    Product* SellProduct(){ return new Fruit(); }

};

//饮料区
class DrinkArea :public Market
{
public:
    DrinkArea(){};
    ~DrinkArea(){};
    Product* SellProduct(){ return new Drink(); }
};
Market* pBiscuitArea = new BiscuitArea();
Product* pBiscuit = pBiscuitArea->SellProduct();
    pBiscuit->Show();

Market* pFruitArea = new FruitArea();
Product* pFruit = pFruitArea->SellProduct();
pFruit->Show();

Market* pDrinkArea = new DrinkArea();
Product* pDrink = pDrinkArea->SellProduct();
pDrink->Show();

这里写图片描述

1、分析代码可知,当要创建某一种食品时,只需要实例化它对应的管辖区类(例如,饼干-》饼干区超市子类BiscuitArea),结构清晰

2、同样的,假设现在每种食品有2件,那么用户端操作的代码为:

Market* pBiscuitArea = new BiscuitArea();
    Product* pBiscuit = pBiscuitArea->SellProduct();
    pBiscuit->Show();

    Market* pFruitArea = new FruitArea();
    Product* pFruit = pFruitArea->SellProduct();
    pFruit->Show();

    Market* pDrinkArea = new DrinkArea();
    Product* pDrink = pDrinkArea->SellProduct();
    pDrink->Show();

    Market* pBiscuitArea1 = new BiscuitArea();
    Product* pBiscuit1 = pBiscuitArea1->SellProduct();
    pBiscuit1->Show();

    Market* pFruitArea1 = new FruitArea();
    Product* pFruit1 = pFruitArea1->SellProduct();
    pFruit1->Show();

    Market* pDrinkArea1 = new DrinkArea();
    Product* pDrink1 = pDrinkArea1->SellProduct();
    pDrink->Show();

这里写图片描述

我们发现用户端使用new的次数,并没有减少。似乎减少代码冗余这个功能没有实现???至少在用户端没有减少,我是这么认为的。

3、同样,现在新增了Nut和Bread这2种食品。如何扩展代码呢?
第一:扩展食品派生类

//坚果
class Nut :public Product
{
public:
    Nut(){}
    ~Nut(){}
    void Show(){ cout << "Hi,customers! I'm Nut!" << endl; }
};

//面包
class Bread :public Product
{
public:
    Bread(){}
    ~Bread(){}
    void Show(){ cout << "Hi,customers! I'm Bread!" << endl; }
};

第二:扩展超市子类

//坚果区
class NutArea :public Market
{
public:
    NutArea(){};
    ~NutArea(){};
    Product* SellProduct(){ return new Nut(); }
};

//面包区
class BreadArea :public Market
{
public:
    BreadArea(){};
    ~BreadArea(){};
    Product* SellProduct(){ return new Bread(); }
};

第三:增加用户端代码

Market* pBiscuitArea = new BiscuitArea();
Product* pBiscuit = pBiscuitArea->SellProduct();
pBiscuit->Show();

Market* pFruitArea = new FruitArea();
Product* pFruit = pFruitArea->SellProduct();
pFruit->Show();

Market* pDrinkArea = new DrinkArea();
Product* pDrink = pDrinkArea->SellProduct();
pDrink->Show();

Market* pNutArea = new NutArea();
Product* pNut = pNutArea->SellProduct();
pNut->Show();

Market* pBreadArea = new BreadArea();
Product* pBread = pBreadArea->SellProduct();
pBread->Show();

这里写图片描述

分析上述代码,可以知道,当增加Nut和Bread这2个新品种时,扩展的代码与原始代码基本上没有交集,无非是多增加一个新品种,食品扩展类增加一个派生类,超市子类增加一个,原始代码不会进行修改,因此,功能也无需重新测试。

工厂方法模式:

优点:使得具体化类的工作延迟到了子类中,耦合度低,扩展性好。工厂端符合开闭原则。
缺点:用户端代码并没有实现减少代码冗余的工作。


抽象工厂模式

当前饼干、水果、饮料都统称为食品。超市决定为了使顾客吃的更健康,决定对食品进行分类:成年人食品+儿童食品。则分类如下:

这里写图片描述

在工厂模式的基础上,对Product类进行修改,则可变为AdultProduct和ChildProduct类。相应地,饼干专区(BiscuitArea)的饼干也分别来自这2类中的饼干(ChildBiscuit和AdultBiscuit)。因为篇幅原因,在抽象工厂模式的UML图中,省略了水果的分类。

这里写图片描述

/***************************************
 * Function:    抽象工厂模式
 * @Copyright:
 * Author:      by sun
 * Date:        2016-07-13
 **************************************/


class ChildProduct{
public:
    ChildProduct(){}
    ~ChildProduct(){}
    virtual void Show(){ cout << "Hi,customers! I'm ChildProduct" << endl; }
};

class ChildBiscuit:public ChildProduct
{
public:
    ChildBiscuit(){}
    ~ChildBiscuit(){}
    void Show(){ cout << "Hi,customers! I'm ChildBiscuit" << endl; }
};

class ChildDrink :public ChildProduct
{
public:
    ChildDrink(){}
    ~ChildDrink(){}
    void Show(){ cout << "Hi,customers! I'm ChildDrink" << endl; }
};

class AdultProduct
{
public:
    AdultProduct(){}
    ~AdultProduct(){}
    virtual void Show(){ cout << "Hi, customers! I'm AdultProduct" << endl; }
};

class AdultBiscuit:public AdultProduct
{
public:
    AdultBiscuit(){}
    ~AdultBiscuit(){}
    void Show(){ cout << "Hi,customers! I'm AdultBiscuit" << endl; }

};

class AdultDrink :public AdultProduct
{
public:
    AdultDrink(){}
    ~AdultDrink(){}
    void Show(){ cout << "Hi,customers! I'm AdultDrink" << endl; }

};

class Market
{
public:
    Market(){}
    ~Market(){}
    virtual AdultProduct* SellAdultProduct(){ return new AdultProduct(); }
    virtual ChildProduct* SellChildProduct(){ return new ChildProduct(); }

};

class BiscuitArea :public Market
{
public:
    BiscuitArea(){}
    ~BiscuitArea(){}
    AdultProduct* SellAdultProduct(){ return new AdultBiscuit(); }
    ChildProduct* SellChildProduct(){ return new ChildBiscuit(); }
};

class DrinkArea :public Market
{
public:
    DrinkArea(){}
    ~DrinkArea(){}
    AdultProduct* SellAdultProduct(){ return new AdultDrink(); }
    ChildProduct* SellChildProduct(){ return new ChildDrink(); }
};
Market* pBiscuitArea = new BiscuitArea();
ChildProduct* pChildBiscuit = pBiscuitArea->SellChildProduct();
pChildBiscuit->Show();
AdultProduct* pAdultBiscuit = pBiscuitArea->SellAdultProduct();
pAdultBiscuit->Show();

Market* pDrinkArea = new DrinkArea();
ChildProduct* pChildDrink = pDrinkArea->SellChildProduct();
pChildDrink->Show();
AdultProduct* pAdultDrink = pDrinkArea->SellAdultProduct();
pAdultDrink->Show();

这里写图片描述

这里打破了产品单一的限制,可以对Product进行更为细致的划分,由一个变成了一组。

同样地,当增加Bread和Nut时,我们对之细分为成年人和儿童版。

第一:扩展儿童Nut和Bread

class ChildNut :public ChildProduct
{
public:
    ChildNut(){}
    ~ChildNut(){}
    void Show(){ cout << "Hi,customers! I'm ChildNut" << endl; }
};

class ChildBread :public ChildProduct
{
public:
    ChildBread(){}
    ~ChildBread(){}
    void Show(){ cout << "Hi,customers! I'm ChildBread" << endl; }
};

第二:扩展成年人Bread和Nut

class AdultNut :public AdultProduct
{
public:
    AdultNut(){}
    ~AdultNut(){}
    void Show(){ cout << "Hi,customers! I'm AdultNut" << endl; }

};

class AdultBread :public AdultProduct
{
public:
    AdultBread(){}
    ~AdultBread(){}
    void Show(){ cout << "Hi,customers! I'm AdultBread" << endl; }

};

第三:扩展Nut和Bread的超市子类

class NutArea :public Market
{
public:
    NutArea(){}
    ~NutArea(){}
    AdultProduct* SellAdultProduct(){ return new AdultNut(); }
    ChildProduct* SellChildProduct(){ return new ChildNut(); }
};

class BreadArea :public Market
{
public:
    BreadArea(){}
    ~BreadArea(){}
    AdultProduct* SellAdultProduct(){ return new AdultBread(); }
    ChildProduct* SellChildProduct(){ return new ChildBread(); }
};

第四:增加用户端代码

Market* pBiscuitArea = new BiscuitArea();
    ChildProduct* pChildBiscuit = pBiscuitArea->SellChildProduct();
    pChildBiscuit->Show();
    AdultProduct* pAdultBiscuit = pBiscuitArea->SellAdultProduct();
    pAdultBiscuit->Show();

    Market* pDrinkArea = new DrinkArea();
    ChildProduct* pChildDrink = pDrinkArea->SellChildProduct();
    pChildDrink->Show();
    AdultProduct* pAdultDrink = pDrinkArea->SellAdultProduct();
    pAdultDrink->Show();

    Market* pNutArea = new NutArea();
    ChildProduct* pChildNut = pNutArea->SellChildProduct();
    pChildNut->Show();
    AdultProduct* pAdultNut = pNutArea->SellAdultProduct();
    pAdultNut->Show();

    Market* pBreadArea = new BreadArea();
    ChildProduct* pChildBread = pBreadArea->SellChildProduct();
    pChildBread->Show();
    AdultProduct* pAdultBread = pBreadArea->SellAdultProduct();
    pAdultBread->Show();

这里写图片描述

抽象工厂模式:

优点:将“单一抽象产品类”扩展到“产品族“,产品类型增多
缺点:结构比较臃肿,当产品增多,系统比较庞大,难以管理



参考文献:
1、《GoF+23种设计解析附C++实现》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值