设计模式—创建型模式

不问归期 提交于 2019-11-29 15:04:57

创建型模式

创建型模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 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;
 }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!