设计模式笔记(上) 
代码设计很复杂,但正是因为有了设计模式,才能更简单地理解、描述和解决一个复杂的问题。个人学习设计模式笔记。主要参考《Head
First设计模式》和Wikipedia,youtube上有个系列视频 也非常值得一看
 
chap 1 设计模式入门—策略模式 
定义 
策略模式 Strategy Pattern 
定义了算法簇,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
分析 
环境(Context): 持有一个Strategy的引用 
抽象策略(Strategy): 这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口 
具体策略(ConcreteStrategy): 包装了相关的算法或行为 
 
利用继承设计子类行为,是在编译时静态决定,而且继承的行为相同;而利用组合可扩展对象的行为,就可在运行时动态地进行扩展。
策略模式=组合composition+委托delegation,实现运行时具有继承行为
设计原则 
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起 
针对接口编程,而不是针对实现编程 
多用组合,少用继承 
 
模式是针对设计问题的通用解决方案,大多数模式都允许局部改变独立于其他部分。
UML 
https://en.wikipedia.org/wiki/Strategy_pattern
代码 
下面代码中Duck也可以设计为基类,为了简便这里简化了。
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  <iostream>  #include  <memory>  class  FlyBehavior  {public :    typedef  std::shared_ptr<FlyBehavior> Ptr;     virtual  void  fly ()  =0 ;     virtual  ~FlyBehavior (){}; }; class  FlyWithWings :public  FlyBehavior{public :    void  fly ()  override   {         std::cout<<"I am flying\n" ;     } }; class  FlyNoWay :public  FlyBehavior{public :    void  fly ()  override   {         std::cout<<"I can't fly\n" ;     } }; class  Duck {public :    Duck (const  FlyBehavior::Ptr &flyBehavior) : flyBehavior_ (flyBehavior) {}     void  performFly ()  {flyBehavior_->fly ();} private :    FlyBehavior::Ptr flyBehavior_; }; int  main ()  {    FlyBehavior::Ptr flyBehavior (new  FlyNoWay)  ;     Duck duck (flyBehavior)  ;     duck.performFly ();     return  0 ; } 
 
chap2
让你的对象知悉现况—观察者模式 
定义 
观察者模式 Observer Pattern 
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
分析 
主题(Subject): 一般为接口或类,存储所有观察者的引用。使用一个共同的接口来更新观察者。叫talker,publisher或许更贴切; 
观察者(Observer): 设置为接口,每个实体观察者需要重写接口函数。叫listener,subscriber或许更贴切; 
具体观察者(Concrete
Observer): 实现观察者接口。 
 
观察者和主题之间是松耦合:主题不知道观察者的细节,只知道观察者实现了观察者接口。
从publisher获取数据时,可以通过推push或拉pull 的方式获取数据,推似乎更常见。
有多个subscriber时,不可以依赖特定的通知顺序。
许多GUI框架经常使用观察者模式,如Android中控件的监听事件函数。这里本质是使用回调机制 实现的:publisher触发某种事件后,调用回调函数;subscriber在回调函数中实现相应自定义的功能。在调用回调函数时,可以将参数传递,也可以参数为空。
设计原则 
小技巧:可以通过setChanged()方法标记状态已经改变,然后再通知观察者,这样更有弹性,可以控制通知的时机,比如可以用来避免频繁通知观察者。
UML 
https://en.wikipedia.org/wiki/Observer_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 #include  <iostream>  #include  <memory>  #include  <vector>  class  Observer  {public :    typedef  std::shared_ptr<Observer> Ptr;     virtual  void  update (std::string event)  =0 ;     virtual  ~Observer (){}; }; class  ObserverOne :public  Observer{public :    void  update (std::string event)  override   {         std::cout<<"Observer One received response: " +event<<std::endl;     } }; class  ObserverTwo :public  Observer{public :    void  update (std::string event)  override   {         std::cout<<"Observer Two received response: " +event<<std::endl;     } }; class  EventSource  {public :    void  addObserver (const  Observer::Ptr& observer)  {observers_.push_back (observer);}     void  scanInput ()  {         std::string input;         while  (std::getline (std::cin,input)){             notifyObserver (input);         }     } private :    void  notifyObserver (std::string event)  {         for (auto  item:observers_)             item->update (event);     }     std::vector<Observer::Ptr> observers_; }; int  main ()  {    Observer::Ptr observer1 (new  ObserverOne)  ;     Observer::Ptr observer2 (new  ObserverTwo)  ;     EventSource eventSource;     eventSource.addObserver (observer1);     eventSource.addObserver (observer2);     eventSource.scanInput ();     return  0 ; } 
 
chap3 装饰对象—装饰者模式 
定义 
装饰者模式Decorator Pattern 
动态地将责任附加到对象上,若要有扩展功能,装饰者提供了比继承更有弹性的替代方案。
分析 
装饰者(Decorator): 继承自组件类,包含组件引用以达到包装wrap目的,通过该引用可以调用装饰之前组件对象的方法(即转发forward),并重写一些需要修改需求的方法,以达到装饰的目的 
组件(Component): 为抽象类,是具体构件和抽象装饰类的共同父类 
 
因为装饰者必须能够取代被装饰者(组件),因此继承 在这里的作用是达到"类型匹配",而不是利用继承去获得"行为"。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。
许多Java
I/O相关类使用的就是装饰者模式,如FilterInputStream等。可以用许多装饰者包装一个组件,但这样也会造成出现许多小对象,使程序结构变得复杂。
设计原则 
转发forward 与委托delegation 二者比较相近,但有区别:
下面是一个Java中例子,来自Wikipedia。Printer包含一个print方法,但是该方法自己没有具体实现,而是把责任转发给了RealPrinter的一个对象。在外界看来,好像是Printer输出了字符串,但实际是RealPrinter做了实际的工作。
划重点:转发即把锅甩给别人
应用:Chain-of-responsibility pattern、Decorator
pattern 、Proxy pattern等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  RealPrinter   {		void  print ()   {  		System.out.println("Hello world!" );  	}  }  class  Printer   {	 	RealPrinter p = new  RealPrinter();	 	void  print ()   { 		p.print();  	}  }     public  class  Main   { 	public  static  void  main (String[] arguments)   {                  		Printer printer = new  Printer(); 		printer.print(); 	}  } 
 
委托和转发比较像,但有一些区别。委托中,self指代sender,而转发中,self指代receiver。或者,按照SO上的一个回答 ,委托算是一种特殊的转发,只不过转发给了接口本身 ,也就是策略模式中的做法。
UML 
https://en.wikipedia.org/wiki/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 #include  <iostream>  #include  <string>  class  Beverage {public :    virtual  double  cost ()  =0 ;     virtual  ~Beverage () {} }; class  Espresso :public  Beverage{public :    double  cost ()  override   {         return  1.99 ;     } }; class  Mocha :public  Beverage{public :    Mocha (Beverage *beverage) : beverage_ (beverage) {}     double  cost ()  override   {         return  beverage_->cost ()+.20 ;     } private :    Beverage* beverage_; }; int  main ()   {    Espresso coffee;     std::cout<<"original coffee: " <<coffee.cost ()<<std::endl;     Beverage* coffee_with_mocha=new  Mocha (&coffee);     coffee_with_mocha=new  Mocha (coffee_with_mocha);     std::cout<<"coffee with double mocha: " <<coffee_with_mocha->cost ()<<std::endl;     return  0 ; } 
 
chap 4
烘烤松耦合OO设计—工厂模式 
书中分为了三种 ,即简单工厂模式、工厂方法模式和抽象工厂模式。
本节UML请参考书上
简单工厂模式 
简单工厂模式其实并不算是一种设计模式,更多的时候是一种编程习惯。
定义 
定义一个 工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。
分析 
根据single
responsibility 原则,将对象创建工作单独分离出来一个类来做,这个类即工厂类,工厂类把全部的创建工作在一个地方处理完了。
代码 
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 #include  <iostream>  #include  <memory>  class  Shape {public :    typedef  std::shared_ptr<Shape> Ptr;     virtual  void  draw ()  =0 ;     virtual  ~Shape () {} }; class  Circle :public  Shape{public :    void  draw ()  override   {         std::cout<<"draw: circle\n" ;     } }; class  Rectangle :public  Shape{public :    void  draw ()  override   {         std::cout<<"draw: rectangle\n" ;     } }; class  ShapeFactory {public :    Shape::Ptr createShape (std::string type)  {         Shape::Ptr shape;         if  (type=="circle" )             shape=Shape::Ptr (new  Circle);         else  if  (type=="rect" )             shape=Shape::Ptr (new  Rectangle);         return  shape;     } }; int  main ()  {    ShapeFactory shapeFactory;     Shape::Ptr circle=shapeFactory.createShape ("circle" );     circle->draw ();     Shape::Ptr rect=shapeFactory.createShape ("rect" );     rect->draw ();     return  0 ; } 
 
工厂方法模式 
通常所说的工厂模式指的是这种模式,工厂方法模式是日常开发中使用频率最高的一种设计模式。
定义 
定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
分析 
工厂方法模式,又叫多态工厂模式。从这个名字,就可以看出其特点。简单工厂只有一个统一的工厂类,所有创建工作在一个地方都处理完了;而工厂方法是有许多工厂类,这些工厂类都实现了一个工厂基类。每一个工厂子类看起来就像简单工厂一样。
代码 
下面代码中,每个工厂类对应了一个product创建,也可以对应多个product创建(这时可能需要在构造时传入参数等,像简单工厂模式那样)。注意将下面代码和简单工厂代码对比。
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 #include  <iostream>  #include  <memory>  class  Shape {public :    typedef  std::shared_ptr<Shape> Ptr;     virtual  void  draw ()  =0 ;     virtual  ~Shape () {} }; class  Circle :public  Shape{public :    void  draw ()  override   {         std::cout<<"draw: circle\n" ;     } }; class  Rectangle :public  Shape{public :    void  draw ()  override   {         std::cout<<"draw: rectangle\n" ;     } }; class  Factory {public :    typedef  std::shared_ptr<Factory> Ptr;     virtual  Shape::Ptr createShape ()  =0 ;     virtual  ~Factory () {} }; class  CircleFactory :public  Factory{public :    Shape::Ptr createShape ()  override   {         return  Shape::Ptr (new  Circle);     } }; class  RectFactory :public  Factory{public :    Shape::Ptr createShape ()  override   {         return  Shape::Ptr (new  Rectangle);     } }; int  main ()  {    Factory::Ptr factory (new  CircleFactory)  ;     Shape::Ptr circle=factory->createShape ();     circle->draw ();     Factory::Ptr factory2 (new  RectFactory)  ;     Shape::Ptr rect=factory2->createShape ();     rect->draw ();     return  0 ; } 
 
抽象工厂模式 
定义 
提供一个接口,用于创建相关或依赖 对象的家族 ,而不需要明确指定具体类。(
在抽象工厂模式中,每一个具体工厂都提供了多个 工厂方法用于产生多种不同类型的对象)
分析 
作用:把搭配的一系列对象捆绑在一起生产 ,比如下面代码中的例子。
角色:
AbstractFactory(抽象工厂) :声明了一组 用于创建对象的方法,注意是一组对象,而且这一组对象是搭配match 的; 
ConcreteFactory(具体工厂) :它实现了在抽象工厂中声明的创建对象的方法,生成一组 具体对象; 
AbstractProduct(抽象产品) :它为每种对象声明接口,在其中声明了对象所具有的业务方法; 
ConcreteProduct(具体产品) :它定义具体工厂生产的具体对象。 
 
抽象工厂的每个方法 实际上看像是工厂方法:每个方法都被声明为抽象,而工厂子类的方法覆盖这些方法来创建某些对象。
工厂方法每个只能创建"一个产品",而抽象工厂可以创建"一个家族产品"。
但该模式不符合开闭原则,如果加入新的产品就必须改变接口。
代码 
抽象工厂模式擅长把搭配的一系列对象捆绑在一起生产,比如下面的例子。如果在生产UI控件时,把Android风格的Text控件和IOS风格的Button控件混在一起了,那将十分糟糕。而使用抽象工厂模式,可以看到可以创建相关或依赖 对象的家族 ,从而避免了把不搭的对象一起生产。youtube那个系列视频的这一节讲的很清楚,可以参考下。
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 #include  <iostream>  #include  <memory>  class  Text {public :    typedef  std::shared_ptr<Text> Ptr;     virtual  void  showText ()  =0 ;     virtual  ~Text () {} }; class  Button {public :    typedef  std::shared_ptr<Button> Ptr;     virtual  void  showButton ()  =0 ;     virtual  ~Button () {} }; class  TextAndroid :public  Text{public :    void  showText ()  override   {         std::cout<<"Text in Android\n" ;     } }; class  TextIOS :public  Text{public :    void  showText ()  override   {         std::cout<<"Text in IOS\n" ;     } }; class  ButtonAndroid :public  Button{public :    void  showButton ()  override   {         std::cout<<"Button in Android\n" ;     } }; class  ButtonIOS :public  Button{public :    void  showButton ()  override   {         std::cout<<"Button in IOS\n" ;     } }; class  UIFactory {public :    typedef  std::shared_ptr<UIFactory> Ptr;     virtual  Text::Ptr createText ()  =0 ;     virtual  Button::Ptr createButton ()  =0 ;     virtual  ~UIFactory () {} }; class  AndroidUIFactory :public  UIFactory{public :    Text::Ptr createText ()  override   {         return  Text::Ptr (new  TextAndroid);     }     Button::Ptr createButton ()  override   {         return  Button::Ptr (new  ButtonAndroid);     } }; class  IOSUIFactory :public  UIFactory{public :    Text::Ptr createText ()  override   {         return  Text::Ptr (new  TextIOS);     }     Button::Ptr createButton ()  override   {         return  Button::Ptr (new  ButtonIOS);     } }; int  main ()  {    UIFactory::Ptr uiFactory (new  AndroidUIFactory)  ;     Text::Ptr text=uiFactory->createText ();     Button::Ptr button=uiFactory->createButton ();     text->showText ();     button->showButton ();     return  0 ; } 
 
chap5 独一无二的对象—单例模式 
定义 
单例模式Singleton Pattrn 
确保一个类只有一个实例,并提供一个全局访问点。
分析 
一个static变量,一个私有构造函数,一个static方法(getInstance())。
如果考虑多线程,必须进行一些改变,否则可能多个线程同时进入全局访问点中,从而创造多个对象。Java 中,改进方式有三种:
同步getInstance()方法。缺点是效率较低; 
恶汉模式; 
double-checked。首先检查实例是否已创建,如果尚未创建,才进行同步。 
 
UML 
https://en.wikipedia.org/wiki/Singleton_pattern
代码 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Singleton  {public :    static  Singleton &getInstance ()   {         static  Singleton singleton;         return  singleton;     }     Singleton (const  Singleton &) = delete ;     Singleton &operator =(const  Singleton &) = delete ; private :    Singleton () {} }; 
 
 
chap6 封装调用—命令模式 
定义 
命令模式Command Pattern 
将"请求"封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销操作。
分析 
命令Command: 具体命令类的抽象接口; 
具体命令Concrete
Command: 打包运算块(一个接收者和一组动作); 
接收者Receiver: 负责调用命令对象执行请求; 
请求者Invoker: 以委托的形式调用命令。 
 
一个命令对象(ConcreteCommand)通过在特定接收者 上绑定一组动作 来封装 一个请求。即命令对象将一组动作和一个接收者打包 进一个对象中,这个对象只暴露出一个execute()方法,此方法被调用时,接收者就会进行这些动作。这个打包后的对象就像一般的对象一样,可以被存储、传递和调用 。
调用者可接受命令对象当做参数,甚至在运行时动态地进行。
命令支持撤销 ,做法是实现一个undo()方法来回到execute()方法执行前的状态。
宏命令是命令的一种简单延伸,允许调用多个命令 。也支持撤销。
命令模式可以用来实现线程池、工作队列和日志请求 等。如Java中常见的开启新线程就是使用命令模式。其中Runnable接口即Command,new生成的匿名类即Concrete
Command,Thread即Invoker,Receiver省略了,具体的逻辑直接放在了Concrete
Command中。
1 2 3 4 5 6 new  Thread(new  Runnable(){	@Override  	public  void  run ()  { 		 	} }).start(); 
 
UML 
https://en.wikipedia.org/wiki/Command_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 #include  <iostream>  #include  <memory>  class  Light {public :    typedef  std::shared_ptr<Light> Ptr;     void  on ()  {std::cout<<"Light is on\n" ;}     void  off ()  {std::cout<<"Light is off\n" ;} }; class  Command {public :    typedef  std::shared_ptr<Command> Ptr;     virtual  void  execute ()  =0 ;     virtual  ~Command () {} }; class  LightOnCommand :public  Command{public :    LightOnCommand (const  Light::Ptr &light) : light_ (light) {}     void  execute ()  override   {         light_->on ();     } private :    Light::Ptr light_; }; class  Remote {public :    Remote () {}     void  setCommand (Command::Ptr command)  {command_=command;}     void  onButtonWasPressed ()  {command_->execute ();} private :    Command::Ptr command_; }; int  main ()  {    Light::Ptr light (new  Light)  ;     Command::Ptr lightOn (new  LightOnCommand(light))  ;     Remote remote;     remote.setCommand (lightOn);     remote.onButtonWasPressed ();     return  0 ; } 
 
个人理解错误的地方还请不吝赐教,转载请标明出处