天天看點

程式設計模式 之美 -- 抽象工廠模式

文章目錄

  • ​​1. 解決問題​​
  • ​​2. 應用場景​​
  • ​​3. 實作如下:​​
  • ​​C++實作​​
  • ​​C語言實作​​
  • ​​4. 缺點​​

1. 解決問題

在工廠方法模式中,我們賣衣服。此時我們為每一種衣服建立不同的工廠,帽子有一個工廠專門建立,褲子有一個工廠專門建立,T恤有一個工廠專門建立。這樣的方式保證了代碼設計的開閉原則(對擴充開發,對修改關閉),解決了簡單工廠模式中暴露的問題。

但是又凸顯了新的問題,假如現在優衣庫這個大工廠 裡面需要生産不同的種類的衣服,我們需要建立一堆工廠。同時香蕉共和國 這個另一個大工廠也需要生産不同種類的衣服,我們又需要建立一堆工廠。在這種情況下,代碼會增加很多重複邏輯。

于是抽象工廠模式推出,将帽子封裝為一個工廠, 支援生産優衣庫的帽子和香蕉共和國的帽子。将褲子封裝為另一個工廠,用來生産優衣庫的褲子和香蕉共和國的褲子。

2. 應用場景

  • 對象之間存在關聯,兩個對象使用同一個工廠生産,降低程式複雜度,減少不必要的重複邏輯。
  • 系統中有多個産品族,但每次隻使用其中的某一族産品。如有人隻喜歡穿某一個品牌的衣服和鞋
  • 系統中提供了産品的類庫,且所有産品的接口相同,用戶端不依賴産品執行個體的建立細節和内部結構
  • 對象數量比較龐大,維護多個工廠則程式的複雜度過高,由工廠方法模式變更為抽象工廠模式

3. 實作如下:

C++實作

實作功能:仍然是生産衣服,我們使用抽象工廠模式 将優衣庫的帽子和香蕉共和國的帽子統一生産,将優衣庫的褲子和香蕉共和國的褲子統一生産。

#include <iostream>

using namespace std;

class Hat{
    public:
    virtual void createHat(void) = 0;
    virtual ~Hat(){}
};

/*優衣庫的帽子*/
class kuHat: public Hat {
    public:
    kuHat(){
        cout << "kuHat::kuHat()" << endl;
    }
    
    virtual void createHat(void) {
        cout << "kuHat::createHat()" << endl;
    }
    
    ~kuHat(){
        cout << "kuHat::delete()" << endl;
    }    
};

/*香蕉共和國的帽子*/
class bananHat: public Hat{
    public:
    bananHat(){
        cout << "bananHat::bananHat()" << endl;
    }
    
    virtual void createHat(void) {
        cout << "bananHat::createHat()" << endl;
    }
    
    ~bananHat(){
        cout << "bananHat::delete()" << endl;
    }      
};

class Paths{
    public:
    virtual void createPaths(void) = 0;
    virtual ~Paths(){}    
};

/*優衣庫的褲子*/
class kuPaths: public Paths{
    public:
    kuPaths(){
        cout << "kuPaths::kuPaths()" << endl;
    }
    
    virtual void createPaths(void) {
        cout << "kuPaths::createPaths()" << endl;
    }
    
    ~kuPaths(){
        cout << "kuPaths::delete()" << endl;
    }      
};

/*香蕉共和國的褲子*/
class bananPaths: public Paths{
    public:
    bananPaths(){
        cout << "bananPaths::bananPaths()" << endl;
    }
    
    virtual void createPaths(void) {
        cout << "bananPaths::createPaths()" << endl;
    }
    
    ~bananPaths(){
        cout << "bananPaths::delete()" << endl;
    }      
};

/*抽象工廠類*/
class Factory {
    public:
    virtual Hat *createHat() = 0;
    virtual Paths *createPaths() = 0;
};

/*優衣庫的工廠,用來建立優衣庫的衣服*/
class FactoryKu: public Factory{
    public:
    Hat *createHat(){
        return new kuHat();
    }
    
    Paths *createPaths(){
        return new kuPaths();
    }
};

/*香蕉共和國的工廠,用來建立香蕉共和國的衣服*/
class FactoryBanan: public Factory {
    public:
    Hat *createHat(){
        return new bananHat();
    }
    
    Paths *createPaths() {
        return new bananPaths();
    }
};

int main() {
    /*建立一個優衣庫的工廠,進行優衣庫的衣服的生産,包括褲子和帽子*/
    Factory *factory1 = new FactoryKu();
    Hat *kuhat = factory1 -> createHat();
    Paths *kupaths = factory1 -> createPaths();
    
    kuhat -> createHat();
    kupaths -> createPaths();
    
    if(factory1) {
        delete factory1;
        factory1 = NULL;
    }
    
    if(kuhat) {
        delete kuhat;
        kuhat = NULL;
    }
    
    if(kupaths) {
        delete kupaths;
        kupaths = NULL;
    }
    return 0;
}      

編譯運作如下

kuHat::kuHat()
kuPaths::kuPaths()
kuHat::createHat()
kuPaths::createPaths()
kuHat::delete()
kuPaths::delete()      
C語言實作

實作功能:工廠商店分别 售賣白蘋果、紅蘋果、白葡萄、紅葡萄

/*C語言實作抽象工廠模式*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

enum {WHITE,RED};

/*蘋果基類*/
typedef struct _Apple {
  void (*print_apple)(void);
}Apple;

/*葡萄基類*/
typedef struct _Grape {
  void (*print_grape)(void);
}Grape;

void print_white_apple(void) 
{
  printf("I'am a white apple!\n");
  return;
}

void print_red_apple(void)
{
  printf("I'am a red apple!\n");
  return;
}
void print_white_grape(void)
{
  printf("I'am a white grape!\n");
  return;
}
void print_red_grape(void)
{
  printf("I'am a red grape!\n");
  return;
}

/*水果商店*/
typedef struct _FruitShop {
  Apple * (*sell_apple)(void);
  Grape * (*sell_grape)(void);
}FruitShop;

Apple* sell_white_apple(void)
{
  Apple* tmp_apple = (Apple*)malloc(sizeof(Apple));
  assert(NULL != tmp_apple);

  tmp_apple->print_apple = print_white_apple;

  return tmp_apple;
}

Apple* sell_red_apple(void)
{
  Apple* tmp_apple = (Apple*)malloc(sizeof(Apple));
  assert(NULL != tmp_apple);

  tmp_apple->print_apple = print_red_apple;

  return tmp_apple;
}

Grape* sell_white_grape(void)
{
  Grape* tmp_grape = (Grape*)malloc(sizeof(Grape));
  assert(tmp_grape != NULL);

  tmp_grape->print_grape = print_white_grape;
  return tmp_grape;
}
Grape* sell_red_grape(void)
{
  Grape* tmp_grape = (Grape*)malloc(sizeof(Grape));
  assert(tmp_grape);

  tmp_grape->print_grape = print_red_grape;

  return tmp_grape;
}

/*工廠商店,賣不同顔色的蘋果和葡萄*/
FruitShop* create_fruit_shop(int color)
{
  FruitShop* fruitshop = (FruitShop*)malloc(sizeof(FruitShop));
  assert(fruitshop != NULL);

  if (color == WHITE) {
    fruitshop->sell_apple = sell_white_apple;
    fruitshop->sell_grape = sell_white_grape;
  }
  else if (color == RED) {
    fruitshop->sell_apple = sell_red_apple;
    fruitshop->sell_grape = sell_red_grape;
  }

  return fruitshop;
}

int main()
{
  FruitShop* fruitshop = create_fruit_shop(RED);

  Apple *ap = fruitshop->sell_apple();
  Grape *gp = fruitshop->sell_grape();

  ap->print_apple();
  gp->print_grape();

  if (ap != NULL) {
    free(ap);
  }
  if (gp != NULL) {
    free(gp);
  }
  if (fruitshop != NULL) {
    free(fruitshop);
  }

  return 0;
}      
I'am a red apple!
I'am a red grape!      

4. 缺點

  1. 當增加一個新的産品族時隻需增加一個新的具體工廠,不需要修改原代碼,滿足開閉原則。(按照如上C++代碼,我們買衣服,當我們增加一種衣服:裙子的時候,隻需要增加一個新的生産裙子的工廠就可以,不需要修改原的衣服種類的代碼)
  2. 當産品族中需要增加一個新種類的産品時,則所有的工廠類都需要進行修改,不滿足開閉原則。(當我們又增加了名創優品的種類時,我們之前所有的類包括:hat,Paths,還有對應的工廠類都需要修改 )