简单工厂模式

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;//抽象水果
class Fruit{
public:virtual void shoName() = 0;
};//苹果类
class Apple : public Fruit{
public:virtual void shoName(){cout << "我是苹果" << endl;}
};//香蕉类
class Banana : public Fruit{
public:virtual void shoName(){cout << "我是香蕉" << endl;}
};//鸭梨类
class Pear : public Fruit{
public:virtual void shoName(){cout << "我是鸭梨" << endl;}
};//水果工厂
class FruitFactory{
public:static Fruit* CreateFruit(string name){if (name.compare("apple") == 0){return new Apple;}else if (name.compare("banana") == 0){return new Banana;}else if (name.compare("pear") == 0){return new Pear;}}
};//测试
void test01(){Fruit* fruit = NULL;fruit = FruitFactory::CreateFruit("apple");  //工厂生产苹果fruit->shoName();delete fruit;fruit = FruitFactory::CreateFruit("banana"); //工厂生产香蕉fruit->shoName();delete fruit;fruit = FruitFactory::CreateFruit("pear"); //工厂生产鸭梨fruit->shoName();delete fruit;}int main(){test01();return EXIT_SUCCESS;
}
简单工厂模式的优缺点及适用场景

优点:
(1)实现了对象创建和使用的分离。
(2)不需要记住具体类名,记住参数即可,减少使用者记忆量。

缺点:
(1)对工厂类职责过重,一旦不能工作,系统受到影响。
(2)增加系统中类的个数,复杂度和理解度增加。
(3)违反“开闭原则”,添加新产品需要修改工厂逻辑,工厂越来越复杂。

适用场景:

  1. 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

工厂方法模式

工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。
首先完全实现‘开闭原则’,实现了可扩展。

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

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;//抽象水果
class AbstractFruit{
public:virtual void showName() = 0;
};/* 具体水果 start  *///苹果
class Apple : public AbstractFruit{
public:virtual void showName(){cout << "我是苹果" << endl;}
};//香蕉
class Banana : public AbstractFruit{
public:virtual void showName(){cout << "我是香蕉" << endl;}
};//鸭梨
class Pear : public AbstractFruit{
public:virtual void showName(){cout << "我是鸭梨" << endl;}
};/* 具体水果 end  *///抽象工厂
class AbstractFactory{
public:virtual AbstractFruit* CreateFruit() = 0;
};/* 具体工厂类 start *///苹果工厂
class AppleFactory : public AbstractFactory{
public:virtual AbstractFruit* CreateFruit(){return new Apple;}
};//香蕉工厂
class BananaFactory : public AbstractFactory{
public:virtual AbstractFruit* CreateFruit(){return new Banana;}
};//鸭梨工厂
class PearFactory : public AbstractFactory{
public:virtual AbstractFruit* CreateFruit(){return new Pear;}
};/* 具体工厂类 end *///测试
void test01(){AbstractFactory* factory = NULL;AbstractFruit* fruit = NULL;factory = new AppleFactory; //创建苹果工厂fruit = factory->CreateFruit(); //苹果工厂生产苹果fruit->showName();factory = new BananaFactory; //创建香蕉工厂fruit = factory->CreateFruit(); //香蕉工厂生产苹果fruit->showName();factory = new PearFactory; //创建鸭梨工厂fruit = factory->CreateFruit(); //鸭梨工厂生产苹果fruit->showName();}int main(){test01();return EXIT_SUCCESS;
}
工厂方法模式的优缺点及适用场景

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

缺点:
(1)增加系统中类的个数,复杂度和理解度增加。
(2)增加了系统的抽象性和理解难度。

适用场景:

  1. 客户端不知道它所需要的对象的类。
  2. 抽象工厂类通过其子类来指定创建哪个对象。

抽象工厂模式

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

模式中的角色和职责:

抽象工厂(Abstract Factory)角色:它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
具体工厂(Concrete Factory)角色:它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
抽象产品(Abstract Product)角色:它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
具体产品(Concrete Product)角色:它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;//抽象苹果类
class AbstractApple{
public:virtual void showName() = 0;
};//抽象香蕉
class AbstractBanana{
public:virtual void showName() = 0;
};//抽象鸭梨
class AbstractPear{
public:virtual void showName() = 0;
};//中国苹果
class ChineseApple : public AbstractApple{
public:virtual void showName(){cout << "中国苹果" << endl;}
};//美国苹果
class AmericanApple : public AbstractApple{
public:virtual void showName(){cout << "美国苹果" << endl;}
};//日本苹果
class JapaneseApple : public AbstractApple{
public:virtual void showName(){cout << "日本苹果" << endl;}
};//中国香蕉
class ChineseBanana : public AbstractBanana{
public:virtual void showName(){cout << "中国香蕉" << endl;}
};//美国香蕉
class AmericanBanana : public AbstractBanana{
public:virtual void showName(){cout << "美国香蕉" << endl;}
};//日本香蕉
class JapaneseBanana : public AbstractBanana{
public:virtual void showName(){cout << "日本香蕉" << endl;}
};//中国鸭梨
class ChinesePear : public AbstractPear{
public:virtual void showName(){cout << "中国鸭梨" << endl;}
};//美国鸭梨
class AmericanPear : public AbstractPear{
public:virtual void showName(){cout << "美国鸭梨" << endl;}
};//日本鸭梨
class JapanesePear : public AbstractPear{
public:virtual void showName(){cout << "日本鸭梨" << endl;}
};//抽象工厂
class AbstractFactory{
public:virtual AbstractApple* CreateApple() = 0;virtual AbstractBanana* CreateBanana() = 0;virtual AbstractPear* CreatePear() = 0;
};//中国工厂
class ChineseFactory : public AbstractFactory{
public:virtual AbstractApple* CreateApple(){return new ChineseApple;}virtual AbstractBanana* CreateBanana(){return new ChineseBanana;}virtual AbstractPear* CreatePear(){return new ChinesePear;}
};//美国工厂
class AmericanFactory : public AbstractFactory{
public:virtual AbstractApple* CreateApple(){return new AmericanApple;}virtual AbstractBanana* CreateBanana(){return new AmericanBanana;}virtual AbstractPear* CreatePear(){return new AmericanPear;}
};//美国工厂
class JapaneseFactory : public AbstractFactory{
public:virtual AbstractApple* CreateApple(){return new JapaneseApple;}virtual AbstractBanana* CreateBanana(){return new JapaneseBanana;}virtual AbstractPear* CreatePear(){return new JapanesePear;}
};void test01(){AbstractFactory* factory = NULL;AbstractApple* apple = NULL;AbstractBanana* banana = NULL;AbstractPear* pear = NULL;factory = new ChineseFactory; //创建中国工厂apple = factory->CreateApple();banana = factory->CreateBanana();pear = factory->CreatePear();apple->showName();banana->showName();pear->showName();delete pear;delete banana;delete apple;delete factory;factory = new AmericanFactory; //创建美国工厂apple = factory->CreateApple();banana = factory->CreateBanana();pear = factory->CreatePear();apple->showName();banana->showName();pear->showName();delete pear;delete banana;delete apple;delete factory;factory = new JapaneseFactory; //创建日本工厂apple = factory->CreateApple();banana = factory->CreateBanana();pear = factory->CreatePear();apple->showName();banana->showName();pear->showName();delete pear;delete banana;delete apple;delete factory;}int main(){test01();return EXIT_SUCCESS;
}
抽象工厂模式的优缺点及适用场景

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

缺点:
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

适用场景:
(1) 系统中有多于一个的产品族。而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
(2) 产品等级结构稳定。设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

单例模式

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

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

(重点)
如何构建单例:
一是单例模式的类只提供私有的构造函数,
二是类定义中含有一个该类的静态私有对象,
三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;/* 懒汉式 */
class Chairman_lazy{
private:Chairman_lazy(){}
public:static Chairman_lazy* getInstance(){if (s_singleton == NULL){s_singleton = new Chairman_lazy;}return s_singleton;}
private:static Chairman_lazy* s_singleton;
};Chairman_lazy* Chairman_lazy::s_singleton = NULL;void test01(){Chairman_lazy* chairman1 = Chairman_lazy::getInstance();Chairman_lazy* chairman2 = Chairman_lazy::getInstance();if (chairman1 == chairman2){cout << "指向同一个对象!" << endl;}else{cout << "指向不是同一个对象!" << endl;}}/* 饿汉式 */
class Chairman_hangry{
private:Chairman_hangry(){}
public:static Chairman_hangry* getInstance(){return s_singleton;}
private:static Chairman_hangry* s_singleton;
};//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;void test02(){Chairman_hangry* chairman1 = Chairman_hangry::getInstance();Chairman_hangry* chairman2 = Chairman_hangry::getInstance();if (chairman1 == chairman2){cout << "指向同一个对象!" << endl;}else{cout << "指向不是同一个对象!" << endl;}
}int main(){//test01();test02();return EXIT_SUCCESS;
}
单例模式遇到多线程时
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
using namespace std;/* 懒汉式 */
class Chairman_lazy{
private:Chairman_lazy(){}
public:static Chairman_lazy* getInstance(){if (s_singleton == NULL){//Sleep(1000); //等到1000秒s_singleton = new Chairman_lazy;}return s_singleton;}
private:static Chairman_lazy* s_singleton;
};Chairman_lazy* Chairman_lazy::s_singleton = NULL;/* 饿汉式 */
class Chairman_hangry{
private:Chairman_hangry(){}
public:static Chairman_hangry* getInstance(){return s_singleton;}
private:static Chairman_hangry* s_singleton;
};//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;DWORD WINAPI MyThread_hangry(LPVOID lpThreadParameter){Chairman_hangry* chairman = Chairman_hangry::getInstance();cout << "单例对象地址:" << (int*)chairman << endl;return 0;
}//饿汉式单例碰到多线程测试
void test01(){HANDLE handler[10];for (int i = 0; i < 10;i++){handler[i] = CreateThread(NULL, NULL, MyThread_hangry, NULL, NULL, NULL);}}DWORD WINAPI MyThread_lazy(LPVOID lpThreadParameter){Chairman_lazy* chairman = Chairman_lazy::getInstance();cout << "单例对象地址:" << (int*)chairman << endl;return 0;
}//懒汉式单例碰到多线程
void test02(){HANDLE handler[10];for (int i = 0; i < 10; i++){handler[i] = CreateThread(NULL, NULL, MyThread_lazy, NULL, NULL, NULL);}}int main(){test01();test02();return EXIT_SUCCESS;
}运行结果:
饿汉式单例模式的单例对象地址是全部一致的
懒汉式单例模式的单例对象地址都不一致

由上面的结果可知,懒汉式单例模式下的多线程是不安全的。
原因:懒汉式的getInstance语句是这样的:

static Chairman_lazy* getInstance(){if (s_singleton == NULL){//Sleep(1000); //等到1000秒s_singleton = new Chairman_lazy;}return s_singleton;}

假如多个Chairman_lazy* Chairman_lazy::s_singleton = NULL;语句
因为多线程下这些语句会同时执行,那么会同时new很多实例,所以不安全

相反,饿汉模式只会在全局new一个实例,getInstance语句是直接返回指针,所以安全。

单例模式的优缺点及适用场景

优点:
(1)单例模式提供了对唯一实例的受控访问。
(2)节约系统资源。由于在系统内存中只存在一个对象。

缺点:
(1) 扩展略难。单例模式中没有抽象层。
(2) 单例类的职责过重。

适用场景:
(1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
(2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

关于单例对象内存的释放问题

一般一个单例对象占用的内存很少,就算不释放内存也没关系
如果真的想是释放,可以用嵌套类来实现

最重要的一点,之所以不写析构函数,是因为单例模式的实例是存储在堆中,不会自动析构,所以需要借助内嵌类delete触发。

class Chairman_hangry{
private:Chairman_hangry(){}~Chairman_hangry(){}
public:static Chairman_hangry* getInstance(){return s_singleton;}
class Garbo{public:~Garbo(){if(s_singleton!=NULL)delete s_singleton;}
};private:static Chairman_hangry* s_singleton;static Garbo garbo;
};
Chairman_hangry* Chairman_hangry::s_singleton=new Chairman_hangry;
Chairman_hangry::Garbo Chairman_hangry::garbo; //这句很重要

C++设计模式 | 四种创建型模式——简单工厂模式、工厂方法模式、抽象工厂模式、单例模式...相关推荐

  1. 设计模式之六个创建型模式的相关知识,简单易懂。

    一. 简单工厂模式-Simple Factory Pattern 1) 工厂三兄弟之简单工厂模式(一) 工厂模式是最常用的一类创建型设计模式,通常我们所说的工厂模式是指工厂方法模式,它也是使用频率最高 ...

  2. 《深入设计模式》笔记 -创建型模式四、原型模式

    原型模式 亦称: 克隆.Clone.Prototype 意图 原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类. 问题 如果你有一个对象, 并希望生成与其完全相同 ...

  3. Java设计模式之五大创建型模式

    Java设计模式之五大创建型模式 设计模式(23种) 单例模式(Singleton Pattern) 参考链接 概念 使用场景 实现思路 实现方式 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线 ...

  4. java设计模式(一)——五种创建型设计模式

    一.什么是设计模式? 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. ...

  5. 设计模式(20):创建型-抽象工厂模式(Abstract Factory)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  6. 【设计模式·Python】创建型模式

    设计模式中,创建型模式主要由以下几种: 工厂方法模式 抽象工厂模式 建造者模式 原型模式 单例模式 简单工厂模式 不直接向客户暴露对象的实现细节,而是通过一个工厂类来负责创建产品的实例. 角色: 工厂 ...

  7. 《深入设计模式》笔记 -创建型模式二、工厂方法模式

    抽象工厂模式 亦称: Abstract Factory 意图 抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类. 问题 假设你正在开发一款家具商店模拟器. 你的代码中 ...

  8. 《深入设计模式》笔记 -创建型模式三、生成器模式(建造者模式)

    生成器模式 亦称:建造者模式.Builder 意图 生成器模式是一种创建型设计模式, 使你能够分步骤创建复杂对象. 该模式允许你使用相同的创建代码生成不同类型和形式的对象. 问题 假设有这样一个复杂对 ...

  9. 设计模式总结: 5种创建型,7种结构型,11种行为型

    设计模式总结: 5种创建型,7种结构型,11种行为型 (加粗的为常用模式) 5种创建型: 工厂方法模式factory 抽象工厂abstactfactory 单例模式singleton 建造者模式bui ...

最新文章

  1. c# dbgrid数据导出到xlsx和ini中实例
  2. 西南科技大学 计算机组成原理2011-2012,西南科技大学计算机组成原理2010-2011试卷A卷参考答案(2011)...
  3. Windows 7 + Fedora 17 双系统安装详解
  4. Cesium界面学习以及隐藏界面控件
  5. PAT1041 考试座位号 (15 分)
  6. C语言面试题分享(6)
  7. 手游建筑美术资源_建筑商和机械手
  8. Markdown编辑器的使用技巧
  9. Windows button控件(按钮控件)
  10. 实例013:所有水仙花数pyt 打印出所有的“水仙花数“,所谓“水仙花数“是指一个三位数,其各位数字立方和等于该数本身。 例如:153是一个“水仙花数“,因为153=1的三次方+5的三次方+3的三次方
  11. 计算机语言描述正确,关于计算机语言的描述,正确的是( )
  12. makefile编译子目录
  13. excel 序号下拉不能够自动(递增)排序
  14. vant的安装和引入
  15. ubuntu修改u盘权限_Ubuntu下U盘只读文件系统,图标上锁,提示无法修改
  16. 51单片机c语言学习感想,学习51单片机心得体会
  17. 「Java基础」范型
  18. Python和Go语言的区别
  19. 10亿数据找出前100大的数据
  20. 五十二.用户配额管理 云主机类型管理 、 镜像管理 网络管理 案例和实例管理 、 安装额外计算节点...

热门文章

  1. 80c52和ULN2003控制步进电机转动
  2. 优锘科技:扒一扒图化资源申请之三生三世那点事儿
  3. 华为鸿蒙系统什么时候出手机,华为鸿蒙系统什么时候出 是否用于手机还未确定...
  4. vue跳转页面增加等待_vue实现几秒后跳转新页面代码
  5. 陈经纶2021年高考成绩查询时间,最新丨2018人大附等28所北京学校中高考成绩一览...
  6. 上帝视角观看黑客攻防战
  7. warning: require(./admin.php),WordPress提示require_once() Failed opening required的解决方法
  8. 使用 FFmpeg 转换视频/音频格式 | 开源 免费 | 不用套壳软件
  9. 77.Oozie的HA启用
  10. Autosar E2E功能安全算法实现