設計模式—創建型模式

創建型模式

創建型模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用 new 運算符直接實例化對象。
優點:程序在判斷針對某個給定實例需要創建哪些對象時更加靈活。

1、工廠模式

在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。工廠模式作爲一種創建模式,一般在創建複雜對象時,考慮使用;在創建簡單對象時,建議直接new完成一個實例對象的創建。

1.1、簡單工廠模式

主要特點是需要在工廠類中做判斷,從而創造相應的產品,當增加新產品時,需要修改工廠類。使用簡單工廠模式,我們只需要知道具體的產品型號就可以創建一個產品。

缺點:工廠類集中了所有產品類的創建邏輯,如果產品量較大,會使得工廠類變的非常臃腫
在這裏插入圖片描述

/*
1、創建一個 Shape 接口和實現 Shape 接口的實體類。
2、定義工廠類 ShapeFactory。
3、使用 ShapeFactory 來獲取 Shape 對象。它將向 ShapeFactory 傳遞信息(CIRCLE / RECTANGLE / SQUARE),以便獲取它所需對象的類型。
*/
 /*
 關鍵代碼:創建過程在工廠類中完成。
 */
 #include <iostream>
 ​ ​
 //定義產品類型信息
 enum SHAPE_TYPE
 {
     CIRCLE,
     RECTANGLE,
     SQUARE
};

//抽象產品類
class Shape
{
public:
    virtual void draw() = 0;
};

//具體的產品類
class Circle : public Shape
{
public:
    Circle ():Shape(){}
    const void draw() override
    {
        cout <<"Circle "<< endl;
    }
};//具體的產品類
class Square: public Shape
{
public:
    Square():Shape(){}
    const void draw() override
    {
        cout <<"Square"<< endl;
    }
};

class Rectangle: public Shape
{
public:
    Rectangle():Shape(){}
    const void draw() override
    {
        cout <<"Rectangle"<< endl;
    }
};
 
 //工廠類
 class ShapeFactory
 {
 public:
     //根據產品信息創建具體的產品類實例,返回一個抽象產品類
     Shape* getShape(SHAPE_TYPE type)
     {
         switch(type)
         {
         case CIRCLE:
             return new Circle();
         case RECTANGLE:
             return new Rectangle();
         case SQUARE:
             return new Square();
         default:
             return nullptr;
         }
     }
 };int main()
 {
     ShapeFactory* factory = new ShapeFactory();
     Shape* pcircle= factory->getShape(CIRCLE);
     pcircle->draw();
     Shape* prectangle = factory->getShape(RECTANGLE);
     prectangle->draw();
     delete pcircle;
     pcircle= nullptr;
     delete prectangle ;
     prectangle  = nullptr;
     delete factory;
     factory = nullptr;
     return 0;
 }
 

1.2、工廠方法模式

定義一個創建對象的接口,其子類去具體現實這個接口以完成具體的創建工作。如果需要增加新的產品類,只需要擴展一個相應的工廠類即可。

缺點:產品類數據較多時,需要實現大量的工廠類,這無疑增加了代碼量。


/*
1、創建一個 Shape 接口和實現 Shape 接口的實體類。
2、創建一個 ShapeFactory接口和實現 ShapeFactory接口的實體類。
3、根據不同的ShapeFactory實體類獲取所需對象的類型。
*/

 /*
 關鍵代碼:創建過程在其子類執行。
 */#include <iostream>
//抽象產品類
class Shape
{
public:
    virtual void draw() = 0;
};
//抽象工廠類
class ShapeFactory
{
public:
    virtual Shape* getShape() = 0;
};

//具體的產品類
class Circle : public Shape
{
public:
    Circle ():Shape(){}
    const void draw() override
    {
        cout <<"Circle "<< endl;
    }
};//具體的產品類
class Square: public Shape
{
public:
    Square():Shape(){}
    const void draw() override
    {
        cout <<"Square"<< endl;
    }
};

class Rectangle: public Shape
{
public:
    Rectangle():Shape(){}
    const void draw() override
    {
        cout <<"Rectangle"<< endl;
    }
};
 
 //工廠類
 class CircleFactory: public ShapeFactory
 {
 public:
     CircleFactory():ShapeFactory(){}
     Shape* getShape()
     {
        return new Circle();
     }
 };//工廠類
 class RectangleFactory: public ShapeFactory
 {
 public:
     RectangleFactory():ShapeFactory(){}
     Shape* getShape()
     {
        return new Rectangle();
     }
 };
 
  //工廠類
 class SquareFactory: public ShapeFactory
 {
 public:
     SquareFactory():ShapeFactory(){}
     Shape* getShape()
     {
        return new Square();
     }
 };
 
 int main()
 {
     ShapeFactory* pcirclefactory = new CircleFactory();
     Shape* pcircle= pcirclefactory->getShape();
     pcircle->draw();
     ShapeFactory* prectanglefactory = new RectangleFactory();
     Shape* prectangle = prectanglefactory->getShape();
     prectangle->draw();
     
     delete pcircle;
     pcircle= nullptr;
     delete prectangle ;
     prectangle  = nullptr;
     delete pcirclefactory;
     pcirclefactory = nullptr;
     delete prectanglefactory;
     prectanglefactory = nullptr;
     return 0;
 }

1.3、抽象工廠模式

抽象工廠模式提供創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

當存在多個產品系列,而客戶端只使用一個系列的產品時,可以考慮使用抽象工廠模式。

缺點:當增加一個新系列的產品時,不僅需要現實具體的產品類,還需要增加一個新的創建接口,
擴展相對困難。

 /*
 * 關鍵代碼:在一個工廠裏聚合多個同類產品。
 * 以下代碼以白色衣服和黑色衣服爲例,白色衣服爲一個產品系列,黑色衣服爲一個產品系列。白色上衣搭配白色褲子,黑色上衣搭配黑色褲字。每個系列的衣服由一個對應的工廠創建,這樣一個工廠創建的衣服能保證衣服爲同一個系列。
 *///抽象上衣類
 class Coat
 {
 public:
     virtual const string& color() = 0;
 };//黑色上衣類
 class BlackCoat : public Coat
 {
 public:
     BlackCoat():Coat(),m_strColor("Black Coat")
     {
     }const string& color() override
     {
         cout << m_strColor.data() << endl;
         return m_strColor;
     }
 private:
     string m_strColor;
 };//白色上衣類
 class WhiteCoat : public Coat
 {
 public:
     WhiteCoat():Coat(),m_strColor("White Coat")
     {
     }
     const string& color() override
     {
         cout << m_strColor.data() << endl;
         return m_strColor;
     }private:
     string m_strColor;
 };//抽象褲子類
 class Pants
 {
 public:
     virtual const string& color() = 0;
 };//黑色褲子類
 class BlackPants : public Pants
 {
 public:
     BlackPants():Pants(),m_strColor("Black Pants")
     {
     }
     const string& color() override
     {
         cout << m_strColor.data() << endl;
         return m_strColor;
     }private:
     string m_strColor;
 };//白色褲子類
 class WhitePants : public Pants
 {
 public:
     WhitePants():Pants(),m_strColor("White Pants")
     {
     }
     const string& color() override
     {
         cout << m_strColor.data() << endl;
         return m_strColor;
     }private:
     string m_strColor;
 };//抽象工廠類,提供衣服創建接口
 class Factory
 {
 public:
     //上衣創建接口,返回抽象上衣類
     virtual Coat* createCoat() = 0;
     //褲子創建接口,返回抽象褲子類
     virtual Pants* createPants() = 0;
 };//創建白色衣服的工廠類,具體實現創建白色上衣和白色褲子的接口
 class WhiteFactory : public Factory
 {
 public:
     Coat* createCoat() override
     {
         return new WhiteCoat();
     }
 ​
     Pants* createPants() override
     {
         return new WhitePants();
     }
 };//創建黑色衣服的工廠類,具體實現創建黑色上衣和白色褲子的接口
 class BlackFactory : public Factory
 {
     Coat* createCoat() override
     {
         return new BlackCoat();
     }
 ​
     Pants* createPants() override
     {
         return new BlackPants();
     }
 };

2、單例模式

單例模式顧名思義,保證一個類僅可以有一個實例化對象,並且提供一個可以訪問它的全局接口。實現單例模式必須注意一下幾點:

  • 單例類只能由一個實例化對象

  • 單例類必須自己提供一個實例化對象。

  • 單例類必須提供一個可以訪問唯一實例化對象的接口

  • 單例模式分爲懶漢餓漢兩種實現方式。
    在這裏插入圖片描述

2.1、懶漢單例模式

懶漢單利模式:用的時候纔會實例化類實例過程中存在線程安全的問題。在訪問量較小,甚至可能不會去訪問的情況下,採用懶漢實現,這是以時間換空間。

2.1.1、非線程安全的懶漢單例模式

/*
* 關鍵代碼:構造函數是私有的,不能通過賦值運算,拷貝構造等方式實例化對象。
*///懶漢式一般實現:非線程安全,getInstance返回的實例指針需要delete
class Singleton
{
public:
    static Singleton* getInstance();
    ~Singleton(){}private:
    Singleton(){}                                        //構造函數私有
    Singleton(const Singleton& obj) = delete;            //明確拒絕
    Singleton& operator=(const Singleton& obj) = delete; //明確拒絕
    
    static Singleton* m_pSingleton;
};
​
Singleton* Singleton::m_pSingleton = NULL;
​
Singleton* Singleton::getInstance()
{
    if(m_pSingleton == NULL)
    {
        m_pSingleton = new Singleton; 	//沒有加鎖,多線程訪問時出現問題
    }
    return m_pSingleton;
}

2.1.2、線程安全的懶漢單例模式

 std::mutex mt;
 
 class Singleton
 {
 public:
     static Singleton* getInstance();
 private:
     Singleton(){}                                    //構造函數私有
     Singleton(const Singleton&) = delete;            //明確拒絕
     Singleton& operator=(const Singleton&) = delete; //明確拒絕
     static Singleton* m_pSingleton; 
 };
 Singleton* Singleton::m_pSingleton = NULL;
 
 Singleton* Singleton::getInstance()
 {
     if(m_pSingleton == NULL)
     {
         mt.lock();
         if(m_pSingleton == NULL)
         {
             m_pSingleton = new Singleton();
         }
         mt.unlock();
     }
     return m_pSingleton;
 }

2.1.3、返回一個reference指向local static對象(非線程安全)

這種單例模式實現方式多線程可能存在不確定性:任何一種non-const static對象,不論它是local或non-local,在多線程環境下“等待某事發生”都會有麻煩。解決的方法:在程序的單線程啓動階段手工調用所有reference-returning函數。這種實現方式的好處是不需要去delete它。

class Singleton
{
public:
    static Singleton& getInstance();
private:
    Singleton(){}
    Singleton(const Singleton&) = delete;  //明確拒絕
    Singleton& operator=(const Singleton&) = delete; //明確拒絕
};
​​
Singleton& Singleton::getInstance()
{
    static Singleton singleton;
    return singleton;
}

2.2、餓漢單例模式

餓漢:在單例類定義的時候就進行實例化。在訪問量比較大,或者可能訪問的線程比較多時,採用餓漢實現,可以實現更好的性能。這是以空間換時間。

 //餓漢式:線程安全,注意一定要在合適的地方去delete它
 class Singleton
 {
 public:
     static Singleton* getInstance();
 private:
     Singleton(){}                                    //構造函數私有
     Singleton(const Singleton&) = delete;            //明確拒絕
     Singleton& operator=(const Singleton&) = delete; //明確拒絕static Singleton* m_pSingleton;
 };
 ​
 Singleton* Singleton::m_pSingleton = new Singleton(); //單例類定義的時候就進行實例化
 ​
 Singleton* Singleton::getInstance()
 {
     return m_pSingleton;
 }

3、建造者模式

建造者模式:將複雜對象的構建和其表示分離,使得相同的構建過程可以產生不同的表示。

以下情形可以考慮使用建造者模式:

  • 對象的創建複雜,但是其各個部分的子對象創建算法一定。

  • 需求變化大,構造複雜對象的子對象經常變化,但將其組合在一起的算法相對穩定。

建造者模式的優點:

  • 將對象的創建和表示分離,客戶端不需要了解具體的構建細節。

  • 增加新的產品對象時,只需要增加其具體的建造類即可,不需要修改原來的代碼,擴展方便。

  • 產品之間差異性大,內部變化較大、較複雜時不建議使用建造者模式。


/*
*關鍵代碼:建造者類:創建和提供實例; Director類:管理建造出來的實例的依賴關係。
*/#include <iostream>
#include <string>
using namespace std;//具體的產品類
class Order
{
public:
    void setFood(const string &food)
    {
        m_strFood = food;
    }const string &food()
    {
        cout << m_strFood.data() << endl;
        return m_strFood;
    }

    void setDrink(const string &drink)
    {
        m_strDrink = drink;
    }const string &drink()
    {
        cout << m_strDrink << endl;
        return m_strDrink;
    }private : string m_strFood;
    string m_strDrink;
};//抽象建造類,提供建造接口。
class OrderBuilder
{
public:
    virtual ~OrderBuilder()
    {
        cout << "~OrderBuilder()" << endl;
    }
    virtual void setOrderFood() = 0;
    virtual void setOrderDrink() = 0;
    virtual Order *getOrder() = 0;
};//具體的建造類
class VegetarianOrderBuilder : public OrderBuilder
{
public:
    VegetarianOrderBuilder()
    {
        m_pOrder = new Order;
    }~VegetarianOrderBuilder()
    {
        cout << "~VegetarianOrderBuilder()" << endl;
        delete m_pOrder;
        m_pOrder = nullptr;
    }void setOrderFood() override
    {
        m_pOrder->setFood("vegetable salad");
    }void setOrderDrink() override
    {
        m_pOrder->setDrink("water");
    }
    ​
        Order *
        getOrder() override
    {
        return m_pOrder;
    }private : Order *m_pOrder;
};//具體的建造類
class MeatOrderBuilder : public OrderBuilder
{
public:
    MeatOrderBuilder()
    {
        m_pOrder = new Order;
    }
    ~MeatOrderBuilder()
    {
        cout << "~MeatOrderBuilder()" << endl;
        delete m_pOrder;
        m_pOrder = nullptr;
    }void setOrderFood() override
    {
        m_pOrder->setFood("beef");
    }void setOrderDrink() override
    {
        m_pOrder->setDrink("beer");
    }
    ​
        Order *
        getOrder() override
    {
        return m_pOrder;
    }private : Order *m_pOrder;
};//Director類,負責管理實例創建的依賴關係,指揮構建者類創建實例
class Director
{
public:
    Director(OrderBuilder *builder) : m_pOrderBuilder(builder)
    {
    }
    void construct()
    {
        m_pOrderBuilder->setOrderFood();
        m_pOrderBuilder->setOrderDrink();
    }private : OrderBuilder *m_pOrderBuilder;
};int main()
{
    //  MeatOrderBuilder* mBuilder = new MeatOrderBuilder;
    OrderBuilder *mBuilder = new MeatOrderBuilder; //注意抽象構建類必須有虛析構函數,解析時纔會                                                      調用子類的析構函數
    Director *director = new Director(mBuilder);
    director->construct();
    Order *order = mBuilder->getOrder();
    order->food();
    order->drink();delete director;
    director = nullptr;delete mBuilder;
    mBuilder = nullptr;return 0;
}

4、原型模式

原型模式:原型模式是通過拷貝一個現有對象生成新對象的。

以下情形可以考慮使用原型模式:

  • 當new一個對象,非常繁瑣複雜時,可以使用原型模式來進行復制一個對象。比如創建對象時,構造函數的參數很多,而自己又不完全的知道每個參數的意義,就可以使用原型模式來創建一個新的對象,不必去理會創建的過程。

  • 當需要new一個新的對象,這個對象和現有的對象區別不大,我們就可以直接複製一個已有的對象,然後稍加修改。

  • 當需要一個對象副本時,比如需要提供對象的數據,同時又需要避免外部對數據對象進行修改,那就拷貝一個對象副本供外部使用。

在這裏插入圖片描述


 /*
 * 關鍵代碼:拷貝,return new className(*this);
 */
 #include <iostream>
 
 /*
 創建一個抽象類 Shape 和擴展了 Shape 類的實體類。下一步是定義類 ShapeCache,該類把 shape 對象存儲在一個 Hashtable 中,並在請求的時候返回它們的克隆。
 
 */using namespace std;//原型角色:定義用於複製現有實例來生成新實例的方法;
 class Shape
 {
 public:
     virtual Shape* clone()
     {
        return new Shape(*this); //調用Shape(const Shape& obj)函數
     };
     
     
     //關鍵代碼拷貝構造函數
     Shape(const Shape& obj)
     {
         this->id = obj.id;
         this->type = obj.type;
     }
     
     public string getType()
     {
        return type;
     }  
     
     public string getID()
     {
        return id;
     }
     
     public void setID(string sid) 
     {
        id = sid;
     }     
     
     virtual void draw() = 0;
     
 private:
     string id;   
     string type; 
 };//具體原型角色:實現用於複製現有實例來生成新實例的方法
 class Rectangle :public Shape
 {
 public:
     Rectangle():Shape()
      , type("Rectangle")                
     {
     }
     ~Sheep()
     {
     }

    void draw() override
    {
      cout <<"Rectangle"<< endl;
    }
 };
 
  class Circle  :public Shape
 {
 public:
     Circle ():Shape()
      , type("Circle ")                
     {
     }
     ~Sheep()
     {
     }

    void draw() override
    {
      cout <<"Circle "<< endl;
    }
 };
 
  class Square :public Shape
 {
 public:
     Square():Shape()
      , type("Square")                
     {
     }
     ~Sheep()
     {
     }

    void draw() override
    {
      cout <<"Square"<< endl;
    }
 };
//使用者角色:維護一個註冊表,並提供一個找出正確實例原型的方法。最後,提供一個獲取新實例的方法,用來委託複製實例的方法生成新實例。
#include <hash_map>
class ShaleCache
{
  public:
    ShaleCache(){}
    hash_map<string, Square*> shapmap;
    
    void loadCache()
    {
      shapmap["Square"]= new Square();
      shapmap["Circle"]= new Circle();
      shapmap["Rectangle"]= new Rectangle();
    }
  
  
  Shape* getShape(string shapeId) {
      Shape* cachedShape = shapeMap.at(shapeId);
      return (Shape*) cachedShape.clone();
      
  }
 int main()
 {
     ShaleCache* pShaleCache = new ShaleCache();
     pShaleCache->loadCache();
     
     
     Shape * pSquare = pShaleCache->getShape("Square");
     pSquare->draw();
     

     delete pShaleCache;
     pShaleCache = nullptr;
     delete pSquare;
     pSquare = nullptr;
     return 0;
 }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章