随着软件工程的不断发展,除了经典的二十几种设计模式,还有更多设计模式在不断涌现,其中一些设计模式也是值得学习的。
对象池模式
对象池(Object
Pool)是一种创建和管理对象的设计模式,特别适用于需要频繁创建和销毁对象的场景。
它通过复用对象来减少对象的创建和销毁次数,从而提高性能和资源利用率,在资源密集型的应用情景中(如数据库连接、线程、Socket连接、内存分配等),池化的思想被广泛使用。
对象池的实现示例是非常简单直观的,直接看代码即可。
与之不同的是,使用C++实现一个实用的线程池或内存池的代码细节会更加复杂,本文中不作讨论。
示例代码如下
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 #include <iostream> #include <memory> #include <vector> class PooledObject {public : PooledObject () { std::cout << "PooledObject created.\n" ; } ~PooledObject () { std::cout << "PooledObject destroyed.\n" ; } void reset () { std::cout << "PooledObject reset.\n" ; } void doSomething () { std::cout << "PooledObject is doing something.\n" ; } }; class ObjectPool {private : std::vector<std::shared_ptr<PooledObject>> m_pool; public : std::shared_ptr<PooledObject> getObject () { if (m_pool.empty ()) { return std::make_shared <PooledObject>(); } std::shared_ptr<PooledObject> obj = m_pool.back (); m_pool.pop_back (); obj->reset (); return obj; } void returnObject (std::shared_ptr<PooledObject> obj) { m_pool.push_back (obj); } }; int main () { ObjectPool pool; auto obj1 = pool.getObject (); obj1->doSomething (); pool.returnObject (obj1); auto obj2 = pool.getObject (); obj2->doSomething (); return 0 ; }
运行结果如下
1 2 3 4 5 PooledObject created. PooledObject is doing something. PooledObject reset. PooledObject is doing something. PooledObject destroyed.
订阅发布模式
订阅发布模式是一种消息传递模式,允许发送者(发布者)和接收者(订阅者)彼此解耦。
在逻辑上主要包括三部分:
发布者(Publisher):发布消息的对象。
订阅者(Subscriber):接收消息的对象。
事件总线(Event Bus):管理发布者和订阅者之间的通信桥梁。
发布者将特定主题的消息发布到一个事件总线上,而订阅者通过事件总线订阅一个或多个主题。
当有新的消息发布时,所有订阅了该主题的订阅者都会收到通知。
示例代码如下
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 #include <iostream> #include <memory> #include <string> #include <unordered_map> #include <utility> #include <vector> class Subscriber {public : virtual ~Subscriber () = default ; virtual void onMessage (const std::string &message) = 0 ; }; class EventBus {public : void addsubscriber (const std::string &topic, std::shared_ptr<Subscriber> subscriber) { m_subscribers[topic].push_back (subscriber); } void publish (const std::string &topic, const std::string &message) { if (m_subscribers.find (topic) != m_subscribers.end ()) { for (auto &subscriber : m_subscribers[topic]) { subscriber->onMessage (message); } } } private : std::unordered_map<std::string, std::vector<std::shared_ptr<Subscriber>>> m_subscribers; }; class Publisher {public : explicit Publisher (EventBus &eventBus) : m_eventBus(eventBus) { } void publishMessage (const std::string &topic, const std::string &message) { m_eventBus.publish (topic, message); } private : EventBus &m_eventBus; }; class NewsSubscriber : public Subscriber {public : explicit NewsSubscriber (std::string name) : m_name(std::move(name)) { } void onMessage (const std::string &message) override { std::cout << m_name << " received news: " << message << '\n' ; } private : std::string m_name; }; class SportsSubscriber : public Subscriber {public : explicit SportsSubscriber (std::string name) : m_name(std::move(name)) { } void onMessage (const std::string &message) override { std::cout << m_name << " received sports news: " << message << '\n' ; } private : std::string m_name; }; int main () { EventBus eventBus; auto newsSubscriber1 = std::make_shared <NewsSubscriber>("News Subscriber 1" ); auto newsSubscriber2 = std::make_shared <NewsSubscriber>("News Subscriber 2" ); auto sportsSubscriber1 = std::make_shared <SportsSubscriber>("Sports Subscriber 1" ); eventBus.addsubscriber ("news" , newsSubscriber1); eventBus.addsubscriber ("news" , newsSubscriber2); eventBus.addsubscriber ("sports" , sportsSubscriber1); Publisher newsPublisher (eventBus) ; Publisher sportsPublisher (eventBus) ; newsPublisher.publishMessage ("news" , "Breaking news: C++20 released!" ); sportsPublisher.publishMessage ("sports" , "New world record set in marathon!" ); return 0 ; }
运行结果如下
1 2 3 News Subscriber 1 received news: Breaking news: C++20 released! News Subscriber 2 received news: Breaking news: C++20 released! Sports Subscriber 1 received sports news: New world record set in marathon!
订阅发布模式与观察者模式经常被用来对比,两者有很多相似之处,但是也有如下的不同点:
解耦程度:
观察者模式:观察者和被观察者之间存在直接的关联。被观察者需要维护着观察者的列表,并在状态变化时通知这些观察者。
订阅发布模式:发布者和订阅者完全解耦,彼此不知道对方的存在。
通信机制:
观察者模式:被观察者直接调用观察者的更新方法,通知它们状态变化。
订阅发布模式:所有的通信都基于事件总线进行,消息通过事件总线分发给订阅者。
使用场景:
观察者模式:适用于一个对象的状态变化需要通知多个依赖对象的场景,适合较简单的同步通信场景。
订阅发布模式:适用于需要解耦多个组件之间通信的场景,如事件驱动系统、消息队列系统等,适合更复杂的同步或异步通信场景。
事实上,我们可以将订阅发布模式视作广义的观察者模式,订阅发布模式还明显的吸收了中介模式中的部分做法。