前言
设计模式:就是在解决某一类问题场景时,有既定的优秀的代码框架可以直接使用,有以下优点可取:
(1)代码更易于维护,代码的可读性、复用性、可移植性、健壮性更好。
(2)当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够做到软件设计要求的"开-闭原则",即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活。
(3)合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的“高内聚,低耦合”这一根本原则。
单例模式
单例模式顾名思义,保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。这是一个创建性模式(主要是指对象的创建方式)。单例模式和多线程结合到是很紧密的。包括两种单例模式,以及线程安全的问题。
应用
第一种:日志模块
假如 这里有一个类,提供了很多方法来封装了一个日志模块。一个软件本身可能有很多的功能模块,那么这么多的模块都要通过日志模块进行写入一些软件运行的日志信息到磁盘内。应该是把这些所有的日志信息都给到一个日志模块的对象上。
第二种:数据库模块
作为一个个的数据库客户端,是要通过数据库模块与数据库服务器进行交互通信的。那么这个数据库client就可以设计成一个单例:应用软件的其他功能模块如果要与数据库服务器进行交互通信,可以调用一个数据库模块对象的某一个方法即可,不需要去创建那么多的对象。毕竟数据库的请求那么多,不可能做到 每一次处理请求都生成一个数据库对象,这样会导致数据库模块对象特别特别多和数据库的连接也特别的多,占用大量内存且非常麻烦。
实现单例模式必须注意一下几点:
(1)单例类只能有一个实例化对象。
(2)单例类必须自己提供一个实例化对象。
(3)单例类必须提供一个可以访问唯一实例化对象的接口。
(4)单例模式分为懒汉和饿汉两种实现方式。
单例:
饿汉式 对象在程序执行时优先创建【线程安全】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <stdio.h> #include <iostream>
using namespace std;
class Singleton { public: static Singleton *getInstance() { return &instance; } Singleton(const Singleton &) = delete; Singleton &operator=(const Singleton &) = delete;
private: static Singleton instance; Singleton() {} }; Singleton Singleton::instance; int main() { Singleton *p1 = Singleton::getInstance(); Singleton *p2 = Singleton::getInstance(); cout << p1 << " " << p2 << endl; return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <stdio.h> #include <iostream>
using namespace std;
class Singleton { public: static Singleton *getInstance() { return &instance; }
private: static Singleton instance; Singleton() {} }; Singleton Singleton::instance;
int main() { Singleton *p1 = Singleton::getInstance(); Singleton *p2 = Singleton::getInstance(); cout << p1 << " " << p2 << endl;
Singleton p = *p1; cout << &p << endl;
return 0; }
|
懒汉式: 对象的创建在第一次调用getInstance函数时创建【线程不安全】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <stdio.h> #include <iostream>
using namespace std;
class Singleton { public: static Singleton *getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } Singleton(const Singleton &) = delete; Singleton &operator=(const Singleton &) = delete;
private: static Singleton *instance; Singleton() {} }; Singleton *Singleton::instance = nullptr; int main() { Singleton *p1 = Singleton::getInstance(); Singleton *p2 = Singleton::getInstance(); cout << p1 << " " << p2 << endl; return 0; }
|
上述懒汉式如何改成线程安全的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include <stdio.h> #include <iostream> #include <mutex> using namespace std;
class Singleton { public: static Singleton *getInstance() { if (instance == nullptr) { unique_lock<mutex>(mtx); if (instance == nullptr) { instance = new Singleton(); } } return instance; } Singleton(const Singleton &) = delete; Singleton &operator=(const Singleton &) = delete;
private: static Singleton *instance; mutex mtx; Singleton() {} }; Singleton *Singleton::instance = nullptr; int main() { Singleton *p1 = Singleton::getInstance(); Singleton *p2 = Singleton::getInstance(); cout << p1 << " " << p2 << endl; return 0; }
|
单例模式缺点
- 全局状态:
- 缺点:单例模式会在应用程序中引入全局状态,这可能导致代码的耦合度增加,使得代码更难以测试和维护。
- 举例:假设你有一个
Logger
单例类,它在整个应用程序中记录日志。如果其他类直接依赖于这个单例类,那么在单元测试中模拟或隔离这个依赖就会变得困难。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Logger { private: Logger() {} static Logger* instance; public: static Logger* getInstance() { if (instance == nullptr) { instance = new Logger(); } return instance; } void log(const std::string& message) { std::cout << message << std::endl; } };
Logger* Logger::instance = nullptr;
void someFunction() { Logger::getInstance()->log("Logging from someFunction"); }
|
在这个例子中,Logger
类是一个单例类。someFunction
函数直接依赖于 Logger
单例类,这使得在单元测试中难以隔离 Logger
类。
- 难以扩展:
- 缺点:由于单例模式限制了类的实例数量,因此很难扩展或修改类的行为。
- 举例:假设你有一个
Configuration
单例类,它存储应用程序的配置信息。如果将来需要支持多个配置实例,那么修改代码将会非常困难。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Configuration { private: Configuration() {} static Configuration* instance; public: static Configuration* getInstance() { if (instance == nullptr) { instance = new Configuration(); } return instance; } void setConfig(const std::string& key, const std::string& value) { } std::string getConfig(const std::string& key) { return "some_config_value"; } };
Configuration* Configuration::instance = nullptr;
void someFunction() { Configuration::getInstance()->setConfig("key", "value"); std::string value = Configuration::getInstance()->getConfig("key"); std::cout << value << std::endl; }
|
在这个例子中,Configuration
类是一个单例类。如果将来需要支持多个配置实例,那么修改代码将会非常困难。
- 线程安全问题:
- 缺点:在多线程环境中,单例模式的实现可能会导致线程安全问题。
- 举例:在多线程环境中,如果没有适当的同步机制,多个线程可能会同时创建单例类的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Singleton { private: Singleton() {} static Singleton* instance; public: static Singleton* getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } };
Singleton* Singleton::instance = nullptr;
|
在这个例子中,Singleton
类的 getInstance
方法不是线程安全的。在多线程环境中,多个线程可能会同时创建 Singleton
类的实例。
为了解决这个问题,可以使用双重检查锁定模式(Double-Checked Locking Pattern)或其他同步机制来确保线程安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <mutex>
class Singleton { private: Singleton() {} static Singleton* instance; static std::mutex mtx; public: static Singleton* getInstance() { if (instance == nullptr) { std::lock_guard<std::mutex> lock(mtx); if (instance == nullptr) { instance = new Singleton(); } } return instance; } };
Singleton* Singleton::instance = nullptr; std::mutex Singleton::mtx;
|
在这个例子中,使用 std::mutex
来确保 getInstance
方法是线程安全的。
简单工厂和工厂方法
简单工厂:它不属于标准的OOP设计模式中,而后面两种是包含在标准的OOP的23种设计模式中的。
为什么要工厂模式:主要是封装了对象的创建过程。 创建性模式本身就是体现了:对象的创建过程的封装和隐藏。没有工厂模式的封装就是:对象的new 和 new等。当代码里面出现很多的类,每次创建在对象的时候,都需要通过new 类名称的方式来生成对象。
先来看个代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <iostream> #include <string>
class Car { public : Car(std::string name):_name(name){}
virtual void show() = 0; protected: std::string _name; };
class BMW:public Car { public: BMW (std::string name):Car(name){} void show() { std::cout << "宝马 " << _name << std::endl; } }; class Audi :public Car { public: Audi(std::string name) :Car(name) {} void show() { std::cout << "奥迪 " << _name << std::endl; } };
int main() { Car* p1 = new BMW("x1"); Car* p2 = new Audi("A6"); p1->show(); p2->show(); delete p1; delete p2;
return 0; }
|
使用简单工厂
解决办法为:把这些对象都给 封装到一个简单的工厂里面。如下:
通过下面这个简单的工厂把所有对象的创建给封装起来了,下面造汽车劳资不用管,我只是想要一辆车,通过传入不同的参数,得到不同的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <iostream> #include <string>
class Car { public: Car(std::string name) : _name(name) {}
virtual void show() = 0; protected: std::string _name; };
class Bmw : public Car { public: Bmw(std::string name) : Car(name) {} void show() { std::cout << "宝马 " << _name << std::endl; } }; class Audi : public Car { public: Audi(std::string name) : Car(name) {} void show() { std::cout << "奥迪 " << _name << std::endl; } }; enum CarType { BMW, AUDI }; class SimpleFactory { public: Car *createCar(CarType type) { switch (type) { case BMW: return new Bmw("x1"); case AUDI: return new Audi("A6"); default: break; } return nullptr; } }; int main() { SimpleFactory *factory = new SimpleFactory(); Car *car1 = factory->createCar(BMW); Car *car2 = factory->createCar(AUDI); car1->show(); car2->show(); delete factory; delete car1; delete car2; return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <stdio.h> #include <iostream> #include <mutex> #include <string> using namespace std;
class F{ public: F(string name):name_(name){} virtual void show() =0; string name_; };
class A:public F{ public: A(string name):F(name){} void show(){ cout<<"AA:"<<name_; } }; class B:public F{ public: B(string name):F(name){} void show(){ cout<<"BB:"<<name_; } };
enum Type{ AA,BB }; class SimpleFactory{ public: F * create(Type type){ switch (type) { case AA: return new A("aaa"); case BB: return new B("bbb"); default: break; } return nullptr; } }; signed main(){ SimpleFactory simpleFactory ; simpleFactory.create(AA)->show(); return 0; }
|
使用智能指针管理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <iostream> #include <string> #include <memory> using namespace std; class Car { public: Car(std::string name) : _name(name) {}
virtual void show() = 0; protected: std::string _name; };
class Bmw : public Car { public: Bmw(std::string name) : Car(name) {} void show() { std::cout << "宝马 " << _name << std::endl; } }; class Audi : public Car { public: Audi(std::string name) : Car(name) {} void show() { std::cout << "奥迪 " << _name << std::endl; } }; enum CarType { BMW, AUDI }; class SimpleFactory { public: Car *createCar(CarType type) { switch (type) { case BMW: return new Bmw("x1"); case AUDI: return new Audi("A6"); default: break; } return nullptr; } }; int main() { std::unique_ptr<SimpleFactory> factory(new SimpleFactory());
std::unique_ptr<Car> car1(factory->createCar(BMW)); std::unique_ptr<Car> car2(factory->createCar(AUDI)); car1->show(); car2->show();
return 0; }
|
简单工厂的缺点:
同一个工厂既建宝马,也整奥迪。不可能用一个工厂把所有对象的创建都封装起来。而且工厂里面的设计也不符合 开闭原则。
开闭原则
开闭原则是面向对象设计的一种重要原则,它的全称是“对扩展开放,对修改关闭”。这个原则的核心思想是,当应用的需求改变时,我们应该尽量通过添加新的代码进行扩展,而不是去修改已有的代码。
具体来说,开闭原则包含两个方面:
- 对扩展开放:意味着我们应该设计出可以容易添加新功能的系统,只需要添加新的代码,而不需要修改原有的代码。
- 对修改关闭:意味着一旦我们完成了系统的设计和编码,应该尽量避免对已有的代码进行修改。因为修改已有的代码会带来很多风险,可能会引入新的错误。
遵守开闭原则的好处是,可以使得系统更加稳定,更具有弹性,更容易进行维护和扩展。但同时,实现开闭原则也需要一定的设计和编码技巧,可能会增加系统的设计和实现的复杂性。
因此,需要根据上述根据对修改关闭,对扩展开放的原则进行修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <iostream> #include <string> #include <memory> using namespace std; class Car { public: Car(std::string name) : _name(name) {}
virtual void show() = 0; protected: std::string _name; };
class Bmw : public Car { public: Bmw(std::string name) : Car(name) {} void show() { std::cout << "宝马 " << _name << std::endl; } }; class Audi : public Car { public: Audi(std::string name) : Car(name) {} void show() { std::cout << "奥迪 " << _name << std::endl; } }; enum CarType { BMW, AUDI }; class SimpleFactory { public: virtual Car *createCar(string name) = 0; }; class BmwFactoryMethod : public SimpleFactory {
Car *createCar(string name) { return new Bmw(name); } }; class AUDIFactoryMethod : public SimpleFactory {
Car *createCar(string name) { return new Audi(name); } }; int main() { std::unique_ptr<SimpleFactory> Afactory(new AUDIFactoryMethod()); std::unique_ptr<SimpleFactory> Bfactory(new BmwFactoryMethod()); std::unique_ptr<Car> car1(Afactory->createCar("x1")); std::unique_ptr<Car> car2(Bfactory->createCar("A5")); car1->show(); car2->show();
return 0; }
|
一种写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <stdio.h> #include <iostream> #include <mutex> #include <string> #include <memory> using namespace std; class F{ public: F(string name):name_(name){} virtual void show() =0; string name_; }; class A:public F{ public: A(string name):F(name){} void show(){ cout<<"AA:"<<name_; } }; class B:public F{ public: B(string name):F(name){} void show(){ cout<<"BB:"<<name_; } }; class SimpleFactory{ public: virtual F* create(string name)=0; }; class AFun:public SimpleFactory{ public: F* create(string name){ return new A(name); } }; signed main(){ unique_ptr<SimpleFactory> nna(new AFun()); unique_ptr<F> aaaa(nna->create("aa")); aaaa->show(); return 0; }
|
把工厂划分为一个继承结构:封装了一个工厂方法(纯虚函数)。派生类代表具体的工厂,产生具体的产品。(相应的工厂创建相应的产品),达到了一个工厂其相应的产品。
这就是对已有的功能进行封闭。开闭原则:对修改关闭,对扩展开放 此时要是删除一种产品的工厂,直接删除相应的派生类即可(也不会改动其他的类)。在调用的时候,想要获取一个对象,只需要调用 工厂相应的工厂方法就可以了,不需要去了解派生类叫什么名字、也不需要知道对象是怎么创建的(这些细节由工厂进行维护)。
抽象工厂
简单工厂的缺点如下:
比如说是 一类有关联关系的产品:手机、手机上的耳机等。根据上面的工厂方法,创建耳机,也得整上一个相应的耳机工厂,这样做 就有些不太现实(具体的一个个工厂类就太多了)。也就是这些一系列有关联关系的产品 应该放在一个工厂进行创建的。 毕竟有关联关系的产品太多了,不可能各个产品都创建相对应的工厂(工厂类将会极为庞大)。
解决方法:将工厂方法升级为抽象工厂。抽象工厂也是需要工厂方法的,抽象工厂:对一系列有关联关系的产品簇提供产品对象的统一创建。
就可以把一组有关联关系的产品簇提供产品对象的统一创建 放到一个工厂里面做了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| #include <iostream> #include <string> #include <memory>
class Car { public: Car(std::string name) : _name(name) {}
virtual void show() = 0; protected: std::string _name; }; class Bmw : public Car { public: Bmw(std::string name) : Car(name) {} void show() { std::cout << "宝马 " << _name << std::endl; } }; class Audi : public Car { public: Audi(std::string name) : Car(name) {} void show() { std::cout << "奥迪 " << _name << std::endl; } };
class CarLight { public: virtual void light() = 0; }; class BmwLight : public CarLight { public: void light() { std::cout << "宝马车灯 " << std::endl; } }; class AudiLight : public CarLight { public: void light() { std::cout << "奥迪车灯 " << std::endl; } };
class AbstractFactory { public: virtual Car *createOneCar(std::string) = 0; virtual CarLight *createCarLight() = 0; };
class BMWAbstractFactory : public AbstractFactory { Car *createOneCar(std::string name) { return new Bmw(name); } CarLight *createCarLight() { return new BmwLight(); } };
class AUDIAbstractFactory : public AbstractFactory { Car *createOneCar(std::string name) { return new Audi(name); } CarLight *createCarLight() { return new AudiLight(); } };
int main() { std::unique_ptr<AbstractFactory> bmwAbstractFactory(new BMWAbstractFactory()); std::unique_ptr<AbstractFactory> audiAbstractFactory(new AUDIAbstractFactory()); std::unique_ptr<Car> p1(bmwAbstractFactory->createOneCar("x1")); std::unique_ptr<Car> p2(audiAbstractFactory->createOneCar("A5"));
std::unique_ptr<CarLight> p3(bmwAbstractFactory->createCarLight()); std::unique_ptr<CarLight> p4(audiAbstractFactory->createCarLight()); p1->show(); p2->show();
p3->light(); p4->light(); return 0; }
|
代理模式
结构型模式:(不是关注于对象的产生,关注于最后通过类与类的组合之后,功能上该怎么使用?以及对问题场景的符合与否?)
这些设计模式关注于类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
代理模式:Proxy Pattern 。主要体现的是 对象访问权限的控制。这个Proxy代理可以把那些访问对象的权限不够的用户 都给挡回去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #include <iostream> #include <string> #include <memory>
class VedioWebSite { public: virtual void freeMovie() = 0; virtual void vipMovie() = 0; virtual void ticketMovie() = 0; };
class OperatorMovieBoss : public VedioWebSite { public: virtual void freeMovie() { std::cout << "你可以看免费电影" << std::endl; } virtual void vipMovie() { std::cout << "你可以看VIP电影" << std::endl; } virtual void ticketMovie() { std::cout << "你可以看VIP + 券电影" << std::endl; } };
class FreeMovieProxy : public VedioWebSite { public: FreeMovieProxy() { pvedio = new OperatorMovieBoss(); } ~FreeMovieProxy() { delete pvedio; } virtual void freeMovie() { pvedio->freeMovie(); } virtual void vipMovie() { std::cout << "你只是普通用户,不可以看VIP电影,请升级为会员" << std::endl; } virtual void ticketMovie() { std::cout << "你没有电源券,不可以观看电影,请先升级为会员然后购买影券" << std::endl; }
private:
VedioWebSite *pvedio; };
class VIPMovieProxy : public VedioWebSite { public: VIPMovieProxy() { pvedio = new OperatorMovieBoss(); } ~VIPMovieProxy() { delete pvedio; } virtual void freeMovie() { pvedio->freeMovie(); } virtual void vipMovie() { pvedio->vipMovie(); } virtual void ticketMovie() { std::cout << "你没有电源券,不可以观看电影,请先购买影券" << std::endl; }
private:
VedioWebSite *pvedio; }; void WhoWatchMovie(std::unique_ptr<VedioWebSite> &ptr) { ptr->freeMovie(); ptr->vipMovie(); ptr->ticketMovie(); } int main() { std::unique_ptr<VedioWebSite> p1(new FreeMovieProxy()); WhoWatchMovie(p1); std::cout << "*****************************" << std::endl; std::unique_ptr<VedioWebSite> p2(new VIPMovieProxy()); WhoWatchMovie(p2);
return 0; }
|
总结:代理模式涉及到了 抽象类(公共类),委托类(需要从抽象类继承而来),代理类(需要从抽象类继承而来),以组合的方式 使用代理对象,在实际的使用中客户直接访问的是代理对象。
装饰器模式
结构型模式的一种:Decorator Pattern
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| #include <iostream> #include <string> #include <memory>
using namespace std;
class Car { public: virtual void show() = 0; };
class Bmw : public Car { public: void show() { cout << "这是宝马汽车的配置为:"; } }; class Audi : public Car { public: void show() { cout << "这是奥迪汽车的配置为:"; } }; class Bnze : public Car { public: void show() { cout << "这是奔驰汽车的配置为:"; } };
class CarBaseDecorator : public Car { public:
virtual void show() = 0; };
class CarChildDecorator1 : public CarBaseDecorator { public: CarChildDecorator1(Car *p) { _ptr = p; } void show() { _ptr->show(); cout << " 定速巡航功能"; }
private: Car *_ptr; };
class CarChildDecorator2 : public CarBaseDecorator { public: CarChildDecorator2(Car *p) { _ptr = p; } void show() { _ptr->show(); cout << " 自动驾驶功能"; }
private: Car *_ptr; };
class CarChildDecorator3 : public CarBaseDecorator { public: CarChildDecorator3(Car *p) { _ptr = p; } void show() { _ptr->show(); cout << " 车道偏离功能"; }
private: Car *_ptr; }; int main() { Car *p1 = new CarChildDecorator1(new Bmw()); p1 = new CarChildDecorator2(p1); p1 = new CarChildDecorator3(p1); p1->show(); cout << endl; cout << "************************************" << endl; Car *p2 = new CarChildDecorator2(new Audi()); p2->show(); cout << endl; cout << "************************************" << endl; Car *p3 = new CarChildDecorator3(new Bnze()); p3->show(); cout << endl; return 0; }
|
从深入理解对象模型的角度看有点套娃的味了,应用了虚函数指针的运行时多态实现。
上述代码详细解释:
在这个代码中,我们使用了装饰器模式,也称为包装器模式。装饰器模式允许我们在运行时动态地添加行为或状态到现有的对象中,而不需要修改其原始类的源代码。
当我们执行 p1->show();
时,输出的结果是 “这是宝马汽车的配置为: 定速巡航功能 自动驾驶功能 车道偏离功能”,这是因为我们在创建 p1
时,逐步地向它添加了这些功能:
Car *p1 = new CarChildDecorator1(new Bmw());
在这一步,我们创建了一个 Bmw
对象,并将其作为参数传递给 CarChildDecorator1
的构造函数。这个操作把 “定速巡航功能” 添加到了 Bmw
对象中。
p1 = new CarChildDecorator2(p1);
在这一步,我们创建了一个 CarChildDecorator2
对象,并将已经包含了 “定速巡航功能” 的 p1
作为参数传递给 CarChildDecorator2
的构造函数。这个操作把 “自动驾驶功能” 添加到了 p1
中。
p1 = new CarChildDecorator3(p1);
在这一步,我们创建了一个 CarChildDecorator3
对象,并将已经包含了 “定速巡航功能” 和 “自动驾驶功能” 的 p1
作为参数传递给 CarChildDecorator3
的构造函数。这个操作把 “车道偏离功能” 添加到了 p1
中。
因此,当我们调用 p1->show();
时,p1
中的每个装饰器都会调用其内部存储的 Car
对象的 show
方法,并在此基础上添加自己的功能描述,从而得到了 “这是宝马汽车的配置为: 定速巡航功能 自动驾驶功能 车道偏离功能” 这个结果。
这就是装饰器模式的魅力,它允许我们动态地添加和组合功能,而不需要修改原始类的代码。
适配器模式
这个适配器有点意思。
在项目中 使用到第三方的插件或者库,但是因为接口不兼容 就需要去添加很多的适配器类。
例如场景:电脑使用一个接口,把桌面演示投影到 投影仪上。
假如:现在有三种类型的接口:VGA HDMI TypeC 。但是目前电脑就用VGA,那么我们就需要用适配器将HDMI转成VGA的格式。把它想成显卡适配器就好理解了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <iostream> #include <string> #include <memory>
using namespace std;
class VGA { public: virtual void play() = 0; };
class TV01 : public VGA { public: void play() { cout << "通过VGA接口连接投影仪,进行视频播放" << endl; } };
class Computer { public: void playVideo(VGA *pVGA) { pVGA->play(); } };
class HDMI { public: virtual void play() = 0; }; class TV02 : public HDMI { public: void play() { cout << "通过HDMI接口连接投影仪,进行视频播放" << endl; } };
class VGAToHDMIAdapter : public VGA { public: VGAToHDMIAdapter(HDMI *p) : pHdmi(p) {} void play() { pHdmi->play(); }
private: HDMI *pHdmi; }; int main() { Computer computer; computer.playVideo(new VGAToHDMIAdapter(new TV02())); return 0; }
|
观察者模式
观察者-监听者模式(发布订阅模式),隶属于行为型模式。
行为型模式:主要关注的是对象之间的通信,例如:对象A调用对象B的成员方法等。
观察者-监听者模式:主要处理 对象的一对多的关系,也就是多个对象都依赖于一个对象。当该对象的状态发生改变时,其他对象都可以接受到相应的通知。假如现在一个类表示了一组数据,生成一个对象。通过这同一个数据对象, 可以得到一组 圆饼图、柱状图、条形图等。
简单解释:
这段代码实现的是发布-订阅模式,也称为观察者模式。这是一种在对象之间定义一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会受到通知并被自动更新。
在这个代码中,Observer
是观察者的抽象基类,Observer1
、Observer2
和 Observer3
都是具体的观察者,他们分别对1、2、3号的消息感兴趣。Subject
是主题类,用来存储每个观察者对哪个消息感兴趣。
当一个消息发生改变时,主题类 Subject
会通过 dispatch
方法找到对这个消息感兴趣的所有观察者,然后调用它们的 upData
方法,通知它们消息已经发生改变。这就是观察者模式的核心。
例如,如果1号消息发生改变,主题类就会找到对1号消息感兴趣的 Observer1
和 Observer2
,然后通知他们。如果2号消息发生改变,主题类就会找到对2号消息感兴趣的 Observer1
和 Observer3
,然后通知他们。如果3号消息发生改变,主题类就会找到对3号消息感兴趣的 Observer2
和 Observer3
,然后通知他们。
这种模式在很多实际应用中都非常有用,比如在GUI编程中,一个按钮的点击事件就可以看作是一个主题,而对这个点击事件感兴趣的所有监听器就是观察者。当用户点击按钮时,所有的监听器都会收到通知。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| #include <iostream> #include <string> #include <unordered_map> #include <list> using namespace std;
class Observer { public: virtual void upData(int messageid) = 0; };
class Observer1 : public Observer { public: void upData(int id) { switch (id) { case 1: cout << "观察者1 对1 和 2号消息感兴趣.1号消息发生改变" << endl; break; case 2: cout << "观察者1 对1 和 2号消息感兴趣.2号消息发生改变" << endl; break; } } }; class Observer2 : public Observer { public: void upData(int id) { switch (id) { case 1: cout << "观察者2 对1 和 3号消息感兴趣.1号消息发生改变" << endl; break; case 3: cout << "观察者2 对1 和 3号消息感兴趣.3号消息发生改变" << endl; break; } } }; class Observer3 : public Observer { public: void upData(int id) { switch (id) { case 2: cout << "观察者3 对2 和 3号消息感兴趣.2号消息发生改变" << endl; break; case 3: cout << "观察者3 对2 和 3号消息感兴趣.3号消息发生改变" << endl; break; } } };
class Subject { public: void addObserver(Observer *obser, int messageid) {
unordered_map<int, list<Observer *>>::iterator it = mapping.find(messageid); if (it != mapping.end()) { it->second.push_back(obser); } else { list<Observer *> mylist; mylist.push_back(obser); mapping.insert({messageid, mylist}); } }
void dispatch(int messageid) { auto it = mapping.find(messageid); if (it != mapping.end()) { for (Observer *pObserver : it->second) { pObserver->upData(messageid); } } }
private: unordered_map<int, list<Observer *>> mapping; }; int main() { Subject subject;
subject.addObserver(new Observer1(), 1); subject.addObserver(new Observer1(), 2);
subject.addObserver(new Observer2(), 1); subject.addObserver(new Observer2(), 3);
subject.addObserver(new Observer3(), 2); subject.addObserver(new Observer3(), 3); cout << "************************************" << endl;
int changeMessid; cout << "请输入一个发生改变的消息 输入-1结束" << endl; cout << "哪个消息改变了:"; while (cin >> changeMessid && changeMessid != -1) { subject.dispatch(changeMessid); cout << "哪个消息改变了:"; } return 0; }
|
理解成发布-订阅模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <iostream> #include <vector> #include <string> #include <algorithm>
class Observer { public: virtual void update(const std::string& message) = 0; virtual ~Observer() {} };
class StockTicker { std::vector<Observer*> observers; public: void attach(Observer* obs) { observers.push_back(obs); }
void detach(Observer* obs) { observers.erase(std::remove(observers.begin(), observers.end(), obs), observers.end()); }
void notify(const std::string& message) { for (Observer* obs : observers) { obs->update(message); } }
void newPriceUpdate(const std::string& stock, double price) { notify("Price updated - " + stock + ": $" + std::to_string(price)); } }; class Investor : public Observer { std::string name; public: Investor(const std::string& name) : name(name) {}
void update(const std::string& message) override { std::cout << name << " received: " << message << std::endl; } };
int main() { StockTicker ticker;
Investor alice("Alice"); Investor bob("Bob");
ticker.attach(&alice); ticker.attach(&bob);
ticker.newPriceUpdate("AAPL", 150.50); ticker.newPriceUpdate("GOOGL", 2729.34);
ticker.detach(&alice); ticker.newPriceUpdate("AAPL", 151.45);
return 0; }
|
学习自: