单列模式,工厂模式,观察者模式 雨点打透心脏的1/2处 2022-07-15 08:10 148阅读 0赞 ## 概述: ## 最近中国股市起起伏伏,当然了起伏就用商机,小明发现商机后果断想入市,买入了中国证券,他想在电脑客户端上,网页上,手机上,iPad上都可以查看到该证券的实时行情,这种情况下我们应该怎么设计我们的软件呢?我们可以这样:小明的所有客户端上都订阅中国证券这个股票,只要股票一有变化,所有的客户端都会被通知到并且被自动更新。 这就是我们的观察者模式,她定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。 ## 类图与实例: ## ![Center][] 可以看出,在这个观察者模式的实现里有下面这些角色: **抽象主题(Subject****)角色**:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。 **抽象观察者(Observer****)角色**:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。 **具体主题(ConcreteSubject****)角色**:将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。 **具体观察者(ConcreteObserver****)角色**:存储与主题的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。 从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要的时候调用每一个观察者共有的Update()方法。这种做法叫做"针对抽象编程"。 **这里我们提供一个简单化的实例:** **\[cpp\]** [view plain][] [copy][view plain] 1. \#include <iostream> 2. \#include <vector> 3. \#include <string> 4. **using****namespace** std; 5. **class** Secretary; 6. // 看股票的同事类(观察对象,观察者) 7. **class** StockObserver 8. \{ 9. **public**: 10. StockObserver(string strName, Secretary\* strSub) 11. \{ 12. name = strName; 13. sub = strSub; 14. \} 15. 16. **void** Update(); 17. 18. **private**: 19. string name; 20. Secretary\* sub; 21. \}; 22. 23. // 秘书类(主题对象,通知者) 24. **class** Secretary 25. \{ 26. 27. **public**: 28. string action; 29. **void** Add(StockObserver ob) \{ observers.push\_back(ob); \} 30. **void** Remove(**int** addIndex) 31. \{ 32. **if**(addIndex >=0 && addIndex < observers.size()) 33. observers.erase(observers.begin() + addIndex); 34. \} 35. **void** Notify() 36. \{ 37. vector<StockObserver>::iterator it; 38. **for** (it=observers.begin(); it!=observers.end(); ++it) 39. \{ 40. (\*it).Update(); 41. \} 42. \} 43. 44. **private**: 45. vector<StockObserver> observers; 46. \}; 47. 48. 49. 50. 51. **void** StockObserver::Update() 52. \{ 53. cout << name << " : " << sub->action << ", begin to work" << endl; 54. \} 55. 56. **int** main() 57. \{ 58. // 创建通知者 59. Secretary\* p = **new** Secretary(); 60. 61. // 观察者 62. StockObserver\* s1 = **new** StockObserver("Lazy", p); 63. StockObserver\* s2 = **new** StockObserver("SnowFire", p); 64. 65. // 加入通知队列 66. p->Add(\*s1); 67. p->Add(\*s2); 68. 69. // 事件 70. p->action = "The boss is coming..."; 71. 72. // 通知 73. p->Notify(); 74. 75. // 动态删除 76. p->Remove(0); 77. 78. p->Notify(); 79. 80. **return** 0; 81. 82. \} ## 适用性: ## 1.当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 2.当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。 3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。 ## 优缺点: ## 观察者模式的效果有以下几个优点: 1.观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。 2.观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。 观察者模式有下面的一些缺点: 1.如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2.如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。 3.如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。 4.虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。 ## 其他: ## 1.在.NET中可以利用Delegate与Event机制来实现观察者模式。 2.Java提供了Observer 和Observable来帮助我们简化实现观察者模式。 # [C++设计模式——工厂方法模式][C] # 2013-11-18 分类:[C++][C 1] / [设计模式][Link 1] 阅读(5845) 评论(58) #### 问题描述 #### 之前讲到了[C++设计模式——简单工厂模式][C 2],由于简单工厂模式的局限性,比如:工厂现在能生产ProductA、ProductB和ProductC三种产品了,此时,需要增加生产ProductD产品;那么,首先是不是需要在产品枚举类型中添加新的产品类型标识,然后,修改Factory类中的switch结构代码。是的,这种对代码的修改,对原有代码的改动量较大,易产生编码上的错误(虽然很简单,如果工程大了,出错也是在所难免的!!!)。这种对代码的修改是最原始,最野蛮的修改,本质上不能称之为对代码的扩展。同时,由于对已经存在的函数进行了修改,那么以前进行过的测试,都将是无效的,所有的测试,都将需要重新进行,所有的代码都需要进行重新覆盖。这种,增加成本,不能提高效率的事情,在公司是绝对不允许的(除非昏庸的PM)。出于种种原因,简单工厂模式,在实际项目中使用的较少。那么该怎么办?怎么办呢?需要对原有代码影响降到最小,同时能对原有功能进行扩展。 #### UML类图 #### 那么今天介绍的工厂方法模式,就隆重登场了。它只是对简单工厂模式的扩展,在GOF的介绍中,它们是合并在一起的,而我则是单独分开进行讲解的,就是为了区分二者的利弊,便于大家在实际项目中进行更好的把握与应用。工厂方法模式是在简单工厂模式的基础上,对“工厂”添加了一个抽象层。将工厂共同的动作抽象出来,作为抽象类,而具体的行为由子类本身去实现,让子类去决定生产什么样的产品。 ![果冻想 | 一个原创文章分享网站][jellythinkFactory_20Pattern.png] 如图,FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。由于FactoryA、FactoryB和FactoryC之间没有关系,当加入FactoryC加入时,对FactoryA和FactoryB的工作没有产生任何影响,那么对代码进行测试时,只需要单独对FactoryC和ProductC进行单元测试,而FactoryA和FactoryB则不用进行测试,则可省去大量无趣无味的测试工作。 #### 适用场合 #### 工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。 1. 在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式; 2. 产品结构较复杂的情况下,可以使用工厂方法模式; 由于使用设计模式是在详细设计时,就需要进行定夺的,所以,需要权衡多方面的因素,而不能为了使用设计模式而使用设计模式。 #### 代码实现 #### /* ** FileName : FactoryMethodPatternDemo ** Author : Jelly Young ** Date : 2013/11/18 ** Description : More information, please go to http://www.jellythink.com */ #include <iostream> using namespace std; class Product { public: virtual void Show() = 0; }; class ProductA : public Product { public: void Show() { cout<< "I'm ProductA"<<endl; } }; class ProductB : public Product { public: void Show() { cout<< "I'm ProductB"<<endl; } }; class Factory { public: virtual Product *CreateProduct() = 0; }; class FactoryA : public Factory { public: Product *CreateProduct() { return new ProductA (); } }; class FactoryB : public Factory { public: Product *CreateProduct() { return new ProductB (); } }; int main(int argc , char *argv []) { Factory *factoryA = new FactoryA (); Product *productA = factoryA->CreateProduct(); productA->Show(); Factory *factoryB = new FactoryB (); Product *productB = factoryB->CreateProduct(); productB->Show(); if (factoryA != NULL) { delete factoryA; factoryA = NULL; } if (productA != NULL) { delete productA; productA = NULL; } if (factoryB != NULL) { delete factoryB; factoryB = NULL; } if (productB != NULL) { delete productB; productB = NULL; } return 0; } 2013年11月18日 于大连、东软。 [Center]: /images/20220715/27a449cac6f94161890757fde3df9566.png [view plain]: http://blog.csdn.net/lcl_data/article/details/9208561# [C]: http://www.jellythink.com/archives/62 [C 1]: http://www.jellythink.com/archives/category/language/cpp [Link 1]: http://www.jellythink.com/archives/category/programdesign/designpattern [C 2]: http://www.jellythink.com/archives/42 [jellythinkFactory_20Pattern.png]: http://picture.jellythink.com/jellythinkFactory%20Pattern.png
还没有评论,来说两句吧...