设计模式笔记(下)
个人学习设计模式笔记。主要参考《Head
First设计模式》和Wikipedia,youtube上有个系列视频 也非常值得一看
chap 7
随遇而安—适配器模式与外观模式
适配器模式
定义
适配器模式Adapter Pattern
将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
分析
目标Target: 接口类;
适配器Adapter: 实现目标接口;
被适配者Adaptee: 适配器的调用委托给被适配者。
这种组合的方式属于对象适配器 ,还有一种利用多重继承的方式,叫类适配器 。即Adapter同时继承Target和Adaptee。对象适配器使用组合,更有弹性,还可以适配被适配类的子类;而类适配器使用继承,不需要重新实现整个被适配者,但不灵活。
UML
https://en.wikipedia.org/wiki/Adapter_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 #include <iostream> #include <memory> class Duck {public : typedef std::shared_ptr<Duck> Ptr; virtual void quack () =0 ; virtual ~Duck () {} }; class Turkey {public : typedef std::shared_ptr<Turkey> Ptr; virtual void gobble () =0 ; virtual ~Turkey () {} }; class WildTurkey :public Turkey{public : void gobble () override { std::cout<<"Gobble gobble\n" ; } }; class TurkeyAdapter :public Duck{public : TurkeyAdapter (const Turkey::Ptr &turkey) : turkey_ (turkey) {} void quack () override { turkey_->gobble (); } private : Turkey::Ptr turkey_; }; int main () { Turkey::Ptr wildTurkey (new WildTurkey) ; Duck::Ptr turkeyAdapter (new TurkeyAdapter(wildTurkey)) ; turkeyAdapter->quack (); return 0 ; }
外观模式
定义
外观模式Facade Pattern
提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
分析
结构上三者类似,但目的不同 :适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;外观将一群对象包装起来以简化接口。
适配器一般只适配一个类,但实际也可以适配许多类来提供一个接口;装饰者一般只包装一个类;外观一般"封装"多个类。
设计原则
UML
https://en.wikipedia.org/wiki/Facade_pattern
代码
略
chap8 封装算法—模板方法模式
定义
模板方法模式Template method pattern
在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
分析
抽象类: 定义算法的框架。包括一些必须子类实现的步骤(抽象方法)、一些可以缺省实现的步骤(虚函数),及一些强制默认实现的步骤(final);
具体类: 抽象类的子类,根据实际需要实现相应步骤。
模板方法模式用于封装算法,把一些步骤的实现强制延迟 到子类,一些缺省实现的步骤叫做"钩子hook",还有一些强制默认实现的步骤声明为final。
策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
工厂方法是模板方法的一个特殊版本。
设计原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
即将决策权放在高层模块中,当需要的时候,自然会去调用子类。
UML
https://en.wikipedia.org/wiki/Template_method_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 #include <iostream> class Beverage {public : void boilWater () {std::cout<<"Boiling water\n" ;} virtual void brew () =0 ; virtual void pourInCup () {} void prepare () { boilWater (); brew (); pourInCup (); } }; class Coffee :public Beverage{public : void brew () override { std::cout<<"Dripping coffee through filter\n" ; } void pourInCup () override { std::cout<<"Pouring into cup\n" ; } }; class Tea :public Beverage{public : void brew () override { std::cout<<"Steeping the tea\n" ; } }; int main () { Coffee coffee; Tea tea; coffee.prepare (); std::cout<<std::endl; tea.prepare (); return 0 ; }
chap9
管理良好的集合—迭代器与组合模式
迭代器模式
定义
迭代器模式Iterator pattern
提供一种方法顺序访问一个集合对象中各个元素,而又不暴露其内部的表示。
分析
迭代器模式在许多语言(c++,java,python等)中都已存在。简单地说,就是将遍历各元素的工作封装进一个对象中。
UML
https://en.wikipedia.org/wiki/Iterator_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 #include <memory> #include <string> #include <vector> #include <iostream> class IIterator {public : typedef std::shared_ptr<IIterator> Ptr; virtual bool hasNext () = 0 ; virtual std::string next () = 0 ; virtual ~IIterator () {} }; class IContainer {public : virtual IIterator::Ptr createIterator () = 0 ; virtual ~IContainer () {} }; class BookIterator : public IIterator {public : BookIterator (const std::vector<std::string> &books) : books_ (books) {} bool hasNext () override { if (position_ >= books_.size ()) return false ; else return true ; } std::string next () override { std::string book = books_[position_]; ++position_; return book; } private : int position_ = 0 ; std::vector<std::string> books_; }; class BooksCollection : public IContainer {public : BooksCollection (const std::vector<std::string> &books) : books_ (books) {} IIterator::Ptr createIterator () override { auto iter = std::make_shared<BookIterator>(books_); return iter; } private : std::vector<std::string> books_; }; int main () { std::vector<std::string> books{"Harry Potter" , "C++ primer" , "Design Pattern" }; BooksCollection booksCollection (books) ; auto iter = booksCollection.createIterator (); while (iter->hasNext ()) std::cout << iter->next () << std::endl; return 0 ; }
组合模式
定义
组合模式Composite pattern
允许你将对象组合成树形结构来表现"整体/部分"层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
分析
Component : 组合接口
Leaf : 叶节点,实现组合接口
Composite :
组合节点,增加子节点管理方法,并委托方法给所有子节点
组合模式允许客户对个别对象以及组合对象一视同仁。
设计原则
UML
https://en.wikipedia.org/wiki/Composite_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 #include <vector> #include <memory> #include <iostream> class Graphic {public : typedef std::shared_ptr<Graphic> Ptr; virtual void print () = 0 ; virtual ~Graphic () {} }; class CompositeGraphic : public Graphic {public : void add (Graphic::Ptr graphic) { childGraphics_.push_back (graphic); } void print () override { for (auto graphic:childGraphics_) graphic->print (); } private : std::vector<Graphic::Ptr> childGraphics_; }; class Ellipse : public Graphic {public : void print () override { std::cout << "Ellipse\n" ; } }; int main () { auto ellipse1 = std::make_shared<Ellipse>(); auto ellipse2 = std::make_shared<Ellipse>(); auto ellipse3 = std::make_shared<Ellipse>(); auto graphic2 = std::make_shared<CompositeGraphic>(); graphic2->add (ellipse1); auto graphic3 = std::make_shared<CompositeGraphic>(); graphic3->add (ellipse2); graphic3->add (ellipse3); auto graphic1 = std::make_shared<CompositeGraphic>(); graphic1->add (graphic2); graphic1->add (graphic3); graphic1->print (); return 0 ; }
chap10 事物的状态—状态模式
定义
状态模式State pattern
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
分析
上下文Context :包含一些状态的引用,并将行为委托给当前状态对象
状态State :定义所有具体状态的共同接口或抽象类
状态模式与有限状态机(finite-state
machine)概念类似,但使用类来表示状态,避免了使用许多条件判断语句,更加有弹性。
状态模式与策略模式类似,仍使用组合composition+委托delegation的形式。但是,策略模式通常会用行为或算法来配置Context类,从而主动控制使用什么样的行为;而状态模式的Context类对象随着时间改变,进而产生不同的行为。
UML
https://en.wikipedia.org/wiki/State_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 #include <memory> #include <string> #include <iostream> #include <boost/algorithm/string.hpp> class State ; class StateContext : public std::enable_shared_from_this<StateContext> {public : using Ptr=std::shared_ptr<StateContext>; StateContext (); void setState (const std::shared_ptr<State> &newState) { state_ = newState; } void writeName (std::string name) ; private : std::shared_ptr<State> state_; }; class State {public : virtual void writeName (const StateContext::Ptr &context, std::string name) = 0 ; virtual ~State () {} }; class LowerCaseState : public State {public : void writeName (const StateContext::Ptr &context, std::string name) override ; }; class MultipleUpperCaseState : public State {public : void writeName (const StateContext::Ptr &context, std::string name) override ; private : int count_ = 0 ; }; void StateContext::writeName (std::string name) { state_->writeName (shared_from_this (), name); } StateContext::StateContext () { state_ = std::make_shared<LowerCaseState>(); } void LowerCaseState::writeName (const StateContext::Ptr &context, std::string name) { std::cout << boost::algorithm::to_lower_copy (name) << std::endl; context->setState (std::make_shared<MultipleUpperCaseState>()); } void MultipleUpperCaseState::writeName (const StateContext::Ptr &context, std::string name) { std::cout << boost::algorithm::to_upper_copy (name) << std::endl; if (++count_ > 1 ) { context->setState (std::make_shared<LowerCaseState>()); } } int main () { auto context = std::make_shared<StateContext>(); context->writeName ("Monday" ); context->writeName ("Tuesday" ); context->writeName ("Wednesday" ); context->writeName ("Thursday" ); context->writeName ("Friday" ); context->writeName ("Saturday" ); context->writeName ("Sunday" ); return 0 ; }
chap11 控制对象访问—代理模式
定义
代理模式Proxy pattern
对另一个对象提供一个替身或占位符以控制对这个对象的访问。
分析
Java远程方法调用(Remote Method
Invocation,RMI)支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
虚拟代理:控制访问开销大的资源
保护代理:基于权限控制对资源的访问
装饰者增加对象行为,代理控制对象的访问。
适配器改变对象适配的接口,而代理实现相同的接口。但保护代理会只提供客户部分接口。
UML
https://en.wikipedia.org/wiki/Proxy_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 #include <iostream> #include <memory> class ICar {public : virtual ~ICar () {} virtual void DriveCar () = 0 ; }; class Car : public ICar {public : void DriveCar () override { std::cout << "Car has been driven!" << std::endl; } }; class ProxyCar : public ICar {public : ProxyCar (int driver_age) : driver_age_ (driver_age) {} void DriveCar () override { if (driver_age_ > 16 ) { real_car_->DriveCar (); } else { std::cout << "Sorry, the driver is too young to drive." << std::endl; } } private : std::unique_ptr<ICar> real_car_ = std::make_unique<Car>(); int driver_age_; }; int main () { std::unique_ptr<ICar> car = std::make_unique<ProxyCar>(16 ); car->DriveCar (); car = std::make_unique<ProxyCar>(25 ); car->DriveCar (); return 0 ; }
chap12 复合模式—模式的模式
MVC模式
模型M:处理。模型利用观察者 让控制器和视图随状态改变而更新
视图V:输出。视图是GUI组件的组合
控制器C:输入。视图和控制器实现策略模式
设计模式分类
创建型。涉及对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦。
Abstract Factory 、Builder、Factory
Method 、Prototype、Singleton
行为型。涉及类和对象如何交互及分配职责。
Chain Of
Responsibility、Command 、Interpreter、Iterator 、Mediator、Memento、Observer 、State 、Strategy 、Template
Method 、Visitor
结构型。让你把类或对象组合到更大的结构中。
Adapter 、Bridge、Composite 、Decorator 、Facade 、Flyweight、Proxy
个人理解错误的地方还请不吝赐教,转载请标明出处