申请书范文网,分享全网优秀范文,学习好帮手!
申请书范文网 > C++设计模式 | 四种创建型模式——简单工厂模式 工厂方法模式 抽象工厂模式 单例模式...

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

时间:2020-06-17 03:28:52

相关推荐

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

简单工厂模式

#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 (pare("apple") == 0){return new Apple;}else if (pare("banana") == 0){return new Banana;}else if (pare("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)违反“开闭原则”,添加新产品需要修改工厂逻辑,工厂越来越复杂。

适用场景:

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

工厂方法模式

工厂方法(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)增加了系统的抽象性和理解难度。

适用场景:

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

抽象工厂模式

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

模式中的角色和职责:

抽象工厂(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; //这句很重要

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。