美文网首页
三、创建型模型

三、创建型模型

作者: 木鱼_cc | 来源:发表于2018-07-07 19:34 被阅读0次
  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式
  4. 单例模式

1.简单工厂模式

简单工厂模式并不属于23种设计模式。

class Fruit
{
  public:
   Fruit(string kind){
     this->kind = kind;
     if(kind == "apple"){
       //代表苹果
       //苹果的初始化方式
     }
     else if(kind == "banana"){
       //代表香蕉
       //香蕉的初始化方式
     }
   }

  void getName(){
    if(this->kind == "apple"){
      cout<<"我是苹果"<<endl;
    }
    else if(this->kind == "banana"){
      cout<<"我是香蕉"<<endl;
    }
  }

  private:
    string kind;
};


int main(){

  //创建一个苹果
  Fruit *apple = new Fruit("apple");
  apple->getName();
  delete apple;

  //main函数跟Fruit类的构造函数耦合度高,随着水果种类的增加 构造函数越来越复杂

  return 0;
}

不难看出,Fruit类是一个“巨大的”类,在该类的设计中存在如下几个问题:
(1) 在Fruit类中包含很多“if…else…”代码块,整个类的代码相当冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且大量条件语句的存在还将影响系统的性能,程序在执行过程中需要做大量的条件判断。
(2) Fruit类的职责过重,它负责初始化和显示所有的水果对象,将各种水果对象的初始化代码和显示代码集中在一个类中实现,违反了“单一职责原则”,不利于类的重用和维护;
(3) 当需要增加新类型的水果时,必须修改Fruit类的源代码,违反了“开闭原则”

1.1模式中的角色和职责

工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
抽象产品(AbstractProduct)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色:简单工厂模式所创建的具体实例对象。

1.png
1.2简单工厂模式案例
2.png
class Fruit
{
  public:
    virtual void getName() = 0;
};

class Apple:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是苹果"<<endl;
    }
};

class Banana:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是香蕉"<<endl;
    }
};

//添加一个新产品 鸭梨
class Pear:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是鸭梨"<<endl;
    }
}

//工厂
class Factory
{
  public:
    Fruit * createFruit(string kind){
      Fruit *f = NULL;
        if(kind == "apple"){
          f = new Apple;
        } 
        else if(kind == "banana"){
          f = new Banana;
        }
        //添加一个鸭梨   修改了工厂的方法 违背的开闭原则!
        else if(kind == "pear"){
          f= new Pear;
        }
      return f;
    }
}

int main(void)
{
  //人们是跟工厂打交道
  Factory *factory = new Factory;//创建一个工厂

  //给我来一个苹果
  Fruit *apple = factory->createFruit("apple");

  apple->getName();


  Fruit *banana = factory->createFruit("banana");
  banana->getName();

  Fruit *pear = factory->createFruit("pear");

  delete apple;
  delete banana;
  delete pear;
  delete factory;

  return 0;
}
1.3简单工厂模式的优缺点

优点:

  • 实现了对象创建和使用的分离
  • 不需要记住具体类名,记住参数即可,减少使用者记忆量

缺点:

  • 对工厂类职责过重,一旦不能工作,系统受到影响。
  • 增加系统中类的个数,复杂度和理解度增加
  • 违反“开闭原则”,添加新产品需要修改工厂逻辑,工厂越来越复杂
1.4使用场景
  • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象并不关心

2.工厂方法模式

2.1工厂方法模式中的角色和职责
3.png

抽象工厂(Abstract Factory)角色:工厂方法模式的核心,任何工厂类都必须实现这个接口。
工厂(Concrete Factory)角色:具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
抽象产品(Abstract Product)角色:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色:工厂方法模式所创建的具体实例对象。

简单工厂模式 + "开闭原则" = 工厂方法模式

2.2工厂方法模式的案例
4.png
#include <iostream>
#include <string>
using namespace std;

//抽象的水果类
class Fruit
{
  public:
    virtual void getName() = 0;
};

class Apple:public Fruit
{
  public:
  virtual void getName(){
    cout<<"我是苹果"<<endl;
  }
};

class Banana:public Fruit
{
  public:
  virtual void getName(){
    cout<<"我是香蕉"<<endl;
  }
};

//添加一个梨产品
class Pear:public Fruit
{
  public:
  virtual void getName(){
    cout<<"我是鸭梨"<<endl;
  }
};

//抽象的工厂类------------------------------
class AbstractFactory
{
  public:
    virtual Fruit * createFruit() = 0;//抽象的工厂生产器
};

//苹果的工厂
class AppleFactory:public AbstractFactory
{
  public:
    virtual Fruit * createFruit(){
      return new Apple;
    }
};

//香蕉工厂
class BananaFactory:public AbstractFactory
{
  public:
    virtual Fruit * createFruit(){
      return new Banana;
    }
};

//新添加梨工厂
class PearFactory:public AbstractFactory
{
  public:
    virtual Fruit *createFruit(){
      return new Pear;
    }
};

int main(void)
{
 
 //1.给我来一个香蕉的工厂
 AbstractFactory *bananaFactory = new BananaFactory;

 //2.给我一个水果
 Fruit* banana = bananaFactory->createFruit();//只能够生成香蕉

 banana->getName();

 delete bananaFactory;
 delete banana;


 AbstractFactory *appleFactory = new AppleFactory;
 Fruit *apple = appleFactory->createFruit();

 apple->getName();

 delete appleFactory;
 delete apple;

  
 AbstractFactory *pearFactory = new PearFactory;
 Fruit *pear = pearFactory->createFruit();

 pear->getName();

 delete pear;
 delete pearFactory;

 return 0;
}
2.3工厂方法模式的优缺点

优点:

  • 不需要记住具体类名,甚至连具体参数都不用记忆
  • 实现了对象创建和使用的分离
  • 系统的可扩展性也就变得非常好,无需修改接口和原类

缺点:

  • 增加系统中类的个数,复杂度和理解度增加
  • 增加了系统的抽象性和理解难度
2.5使用场景
  • 客户端不知道它所需要的对象的类
  • 抽象工厂类通过其子类来指定创建哪个对象

3.抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是我们本文将要学习的抽象工厂模式的基本思想。

“工厂方法模式”实现多区域水果类图
  1. 当我们想添加一个新产品的时候,比如葡萄,虽然不用修改代码,但是我们需要添加大量的类,而且还需要添加相对的工厂。(系统开销,维护成本)
  2. 如果我们使用同一地域的水果(日本🍎 ,日本🍌 ,日本🍐 ),那么我们需要分别创建具体的工厂,如果选择出现失误,将会造成混乱,虽然可以加一些约束,但是代码实现变得复杂。
3.1产品族与产品等级结构
1
3.2模式中的角色和职责
2
  • 抽象工厂(Abstract Factory)角色:它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
  • 具体工厂(Concrete Factory)角色:它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
  • 抽象产品(Abstract Product)角色:它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
  • 具体产品(Concrete Product)角色:它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
3.3抽象工厂模式案例
3
#include <iostream>
#include <string>
using namespace std;

//1.添加一个日本的工厂 和日本的苹果 和香蕉(添加一个产品族)
//针对产品族进行添加 符合开闭

//2.添加一个产品种类,鸭梨(添加一个产品等级结构)
//针对产品等级结构添加 不符合开闭

//3.考虑 1,2是否符合开闭原则


class Fruit
{
  public:
   virtual void getName() = 0;
};

class USAApple:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是美国的苹果"<<endl;
    }
};

class USABanana:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是美国的香蕉"<<endl;
    }
};

class USAPear:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是美国的鸭梨"<<endl;
    }
};

class CNApple:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是中国的苹果"<<endl;
    }
};

class CNBanana:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是中国的香蕉"<<endl;
    }
};

class CNPear:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是中国的鸭梨"<<endl;
    }
};

class JPApple:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是日本的香蕉"<<endl;
    }
};

class JPBanana:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是日本的香蕉"<<endl;
    }
};

class JPPear:public Fruit
{
  public:
    virtual void getName(){
      cout<<"我是日本的鸭梨"<<endl;
    }
};

//定义一个抽象的工厂,是面向产品族进行生产
class AbstractFactory
{
  public:
     virtual Fruit *createApple() = 0;
     virtual Fruit *createBanana() = 0;
     //添加一个鸭梨的生产器
     virtual Fruit *createPear() = 0;
};

//美国的具体工厂
class USAFactory:public AbstractFactory
{
  public:
     virtual Fruit *createApple(){
       return new USAApple;
     }

     virtual Fruit *createBanana(){
       return new USABanana;
     }

     //添加一个美国的生产器
     virtual Fruit *createPear(){
       return new USAPear;
     }
};

//中国的具体工厂
class CNFactory:public AbstractFactory
{
  public:
     virtual Fruit *createApple(){
       return new CNApple;
     }

     virtual Fruit *createBanana(){
       return new CNBanana;
     }

     virtual Fruit *createPear(){
       return new CNPear;
     }
};

//日本的具体工厂
class JPFactory:public AbstractFactory
{
  public:
     virtual Fruit *createApple(){
       return new JPApple;
     }

     virtual Fruit *createBanana(){
       return new JPBanana;
     }

     virtual Fruit *createPear(){
       return new JPPear;
     }
};


int main(void)
{
 
 //想要一个美国的香蕉
 //1.来一个美国的工厂
 AbstractFactory *usaF = new USAFactory;
 Fruit *usaBanana = usaF->createBanana();
 //2.来一个香蕉
 usaBanana->getName();

 delete usaF;
 delete usaBanana;

 
 //想要一个中国的苹果
 AbstractFactory *cnF = new CNFactory;
 Fruit *cnApple = cnF->createApple();

 cnApple->getName();

 delete cnF;
 delete cnApple;

 return 0;
}
3.4抽象工厂模式的优缺点

优点:

  1. 拥有工厂方法模式的优点
  2. 当一个产品族中的多个对象呗设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
  3. 增加新的产品族很方便,无需修改已有系统,符合“开闭原则”

缺点:

  1. 增加新的产品登记结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不变,违背了“开闭原则”。
3.5适用场景
  • 系统中有多于一个的产品族。而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
  • 产品等级结构稳定。设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

工厂三兄弟对比

简单工厂模式 + "开闭原则" = 工厂方法模式
工厂方法模式 + "产品族" = 抽象工厂方法模式

简单工厂模式(规模较小的模型)
工厂方法模式(中等)
抽象工厂方法模式(复杂的产品等级和产品族)

4.单例模式

保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

三个要点:
一是某个类只能有一个实例;
二是它必须自行创建这个实例;
三是它必须自行向整个系统提供这个实例。

4.1模式中的角色和职责
Singleton

Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

单例模式的使用步骤:

  • 构造函数私有化。
  • 提供一个全局的静态方法(全局访问点)来获取单例对象。
  • 在类中定义一个静态指针,指向本类的变量的静态变量指针。
#include <iostream>
using namespace std;

/*
一是某个类只能有一个实例;
二是它必须自行创建这个实例;
三是它必须自行向整个系统提供这个实例。
*/

/*
单例模式的使用步骤:
a)构造函数私有化。  //为了不让在类的外部再创建一个本类的实例
b)提供一个全局的静态方法(全局访问点)来获取单例对象。
c)在类中定义一个静态指针,指向本类的变量的静态变量指针。
*/
class Singleton
{
public:
   static Singleton* getInstance(){
     return instance;
   }
private:
   //不让类的外部再创建实例
   Singleton(){};
   static Singleton *instance;//指向本类位移实例的指针。 放在代码区(全局区)
};

/*
饿汉式——在编译期间就已经确定这个唯一的例子了
*/
Singleton* Singleton::instance = new Singleton;//类的内部


class Singleton2
{
  public:
    static Singleton2* getInstance(){
      //加锁
      if(instace == NULL){
        instance = new Singleton2;
      }
      //释放锁
      return instance;
    }
  private:
     Singleton2(){}
     static Singleton2 *instacne;
};

//懒汉式的初始化方式
Singleton2 *Singleton2::instance = NULL;


int main(void)
{
 
 Singleton *s1 = Singleton::getInstance();
 Singleton *s2 = Singleton::getInstance();

 if(s1 == s2){
   cout<<"s1 == s2"<<endl;
 }
 else{
   cout<<"s1 != s2"<<endl;
 }


 Singleton2 *s3 = Singleton2::getInstance();
 Singleton2 *s4 = Singleton2::getInstance();

 if(s3 == s4){
   cout<<"s3 == s4"<<endl;
 }
 else{
   cout<<"s3 != s4"<<endl;
 }

 return 0;
}
4.2单例模式的应用
4.2.1单例模式的优点
  • 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显
  • 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永远驻留内存的方式来解决。
  • 单例模式可以变对资源的多重启用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  • 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
4.2.2单例模式的缺点
  • 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它要求“自行实例化”,并且提供单一实例、接口或对象类是不可能被实例化的。当然在特殊情况下,单例模式可以实现接口、被继承等,需要在系统开发环境中根据环境判断。
  • 单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象
  • 单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中
4.2.3单例模式的使用场景

在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”,可以采用单例模式,具体的场景如下:

  • 要求生成唯一序列号的环境
  • 在整个项目中需要一个共享访问点或共享数据,例如一个WEB页面上的计数器,可以不用把每次刷新纪录都纪录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的。
  • 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源
  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)
4.3单例练习

用单例模式,模拟公司员工使用打印机场景,打印机可以打印员工要输出的内容,并且可以累积打印机使用次数

#include <iostream>
#include <string>
using namespace std;

class Printer
{
  public:
    static Printer* getInstance(){
      return instance;
    }

    void print(string text){
      cout<<"打印的内容是:"<<text<<endl;
      count++;
    }

    static int getCount(){
      return count;
    }
  private:
     Printer(){};
     static int count;
     static Printer* instance;

    //想回收堆内存也可以,一般不需要你回收!不回收也没什么影响,想回收有以下方法
    //垃圾回收工
     class Garbo{
      private:
        ~Garbo(){
          if(instance != NULL){
            delete instance;
          }
        }
      };

     static Garbo garbo;
}

Printer* Printer::instance = new Printer;
int Printer::count = 0;
Printer::Garbo Printer::Garbo;

int main(void)
{
 
 //员工1 获取
 Printer *p1 = Printer::getInstance();//获取到唯一的打印机实例
 p1->print("一份简历");

 //员工2
 Printer *p2 = Printer::getInstance();
 p2->print("lol 皮肤");

 //员工3
 Printer *p3 = Printer::getInstance();
 p3->print("离职申请");

 int count = Printer::getCount();
 cout<<"今天打印了"<<count<<"份文件"<<endl;

 return 0;
}

相关文章

  • 设计模式概要

    创建型模式:工厂模型,抽象工厂模型,建造模型,原型模型,单例模型,结构型模式:适配器,桥,组合模型,行为型设计模式...

  • iOS 开发的23种设计模式简介

    设计模式主要分三个类型:创建型、结构型和行为型。 其中创建型有: 行为型有: 结构型有:

  • 设计模式--分类

    一、设计模式的分类设计模式可以概括为23种,按照特点可以将其分为三大类型:创建型、结构型、行为型。1、创建型创建型...

  • 需求分析的方法

    1.KANO模型 该模型将需求可以分为三种,包括基本型需求,期望型需求和兴奋型需求。 基本型需求就是必须满足的基础...

  • 模型6:KANO模型-客户满意度

    客户满意度模型Kano KANO模型定义了三个层次的顾客需求:基本型需求、期望型需求和兴奋型需求。这三种需求根据绩...

  • 设计模式之工厂模式

    设计模式中主要分为三大类:创建型、结构型、行为型 工厂模式属于创建型,顾名思义,创建型模式关注对象的创建过程,它将...

  • 极简父母

    九型分三类 性格决定命运 性格里包含 情感模型~NLP 思维模型 行为模型

  • 三、创建型模型

    简单工厂模式 工厂方法模式 抽象工厂模式 单例模式 1.简单工厂模式 简单工厂模式并不属于23种设计模式。 不难看...

  • 设计模式(行为型)-- 观察者模式

    我们常把 23 种经典的设计模式分为三类:创建型、结构型、行为型。创建型设计模式主要解决“对象的创建”问题,结构型...

  • 常见设计模式总结

    分类 设计模式共分为三种类型:创建型、结构型、行为型 创建型:用于创建对象,为设计类实例化新对象提供指南 结构型:...

网友评论

      本文标题:三、创建型模型

      本文链接:https://www.haomeiwen.com/subject/nolwuftx.html