guojh's Blog.

设计模式笔记(下)

字数统计: 2.8k阅读时长: 12 min
2019/09/24

设计模式笔记(下)

个人学习设计模式笔记。主要参考《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>

// target
class Duck{
public:
typedef std::shared_ptr<Duck> Ptr;
virtual void quack()=0;
virtual ~Duck() {}
};

// adaptee
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";
}
};

// adapter
class TurkeyAdapter:public Duck{
public:
TurkeyAdapter(const Turkey::Ptr &turkey) : turkey_(turkey) {}

void quack() override {
turkey_->gobble();
}

private:
Turkey::Ptr turkey_;
};

// test
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>

// abstract class
class Beverage{
public:
void boilWater(){std::cout<<"Boiling water\n";}
virtual void brew()=0;
virtual void pourInCup(){} // hook

void prepare(){
boilWater();
brew();
pourInCup();
}
};

// concrete class
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>

// iterator
class IIterator {
public:
typedef std::shared_ptr<IIterator> Ptr;

virtual bool hasNext() = 0;

virtual std::string next() = 0;

virtual ~IIterator() {}
};

// aggregate
class IContainer {
public:
virtual IIterator::Ptr createIterator() = 0;

virtual ~IContainer() {}
};

// concrete iterator
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_;
};

// concrete aggregate
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>

// component
class Graphic {
public:
typedef std::shared_ptr<Graphic> Ptr;

virtual void print() = 0;

virtual ~Graphic() {}
};

// composite
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_;
};

// leaf
class Ellipse : public Graphic {
public:
void print() override {
std::cout << "Ellipse\n";
}
};

int main() {
//Initialize three ellipses
auto ellipse1 = std::make_shared<Ellipse>();
auto ellipse2 = std::make_shared<Ellipse>();
auto ellipse3 = std::make_shared<Ellipse>();

//Creates two composites containing the ellipses
auto graphic2 = std::make_shared<CompositeGraphic>();
graphic2->add(ellipse1);

auto graphic3 = std::make_shared<CompositeGraphic>();
graphic3->add(ellipse2);
graphic3->add(ellipse3);

//Create another graphics that contains two graphics
auto graphic1 = std::make_shared<CompositeGraphic>();
graphic1->add(graphic2);
graphic1->add(graphic3);

//Prints the complete graphic (Three times the string "Ellipse")
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; // forward declaration
// Context
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_;
};

// State
class State {
public:
virtual void writeName(const StateContext::Ptr &context, std::string name) = 0;

virtual ~State() {}
};

// ConcreteStateA
class LowerCaseState : public State {
public:
void writeName(const StateContext::Ptr &context, std::string name) override;
};

// ConcreteStateB
class MultipleUpperCaseState : public State {
public:
void writeName(const StateContext::Ptr &context, std::string name) override;

private:
int count_ = 0;
};

// definations
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;
// Change state after StateMultipleUpperCase's writeName() gets invoked twice
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");

/* output:
monday
TUESDAY
WEDNESDAY
thursday
FRIDAY
SATURDAY
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>

// subject
class ICar {
public:
virtual ~ICar() {}

virtual void DriveCar() = 0;
};

// real subject
class Car : public ICar {
public:
void DriveCar() override { std::cout << "Car has been driven!" << std::endl; }
};


// proxy
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、ObserverStateStrategyTemplate Method、Visitor

  • 结构型。让你把类或对象组合到更大的结构中。

    Adapter、Bridge、CompositeDecoratorFacade、Flyweight、Proxy

个人理解错误的地方还请不吝赐教,转载请标明出处

CATALOG
  1. 1. 设计模式笔记(下)
    1. 1.1. chap 7 随遇而安—适配器模式与外观模式
      1. 1.1.1. 适配器模式
        1. 1.1.1.1. 定义
        2. 1.1.1.2. 分析
        3. 1.1.1.3. UML
        4. 1.1.1.4. 代码
      2. 1.1.2. 外观模式
        1. 1.1.2.1. 定义
        2. 1.1.2.2. 分析
        3. 1.1.2.3. UML
        4. 1.1.2.4. 代码
    2. 1.2. chap8 封装算法—模板方法模式
      1. 1.2.1. 定义
      2. 1.2.2. 分析
      3. 1.2.3. UML
      4. 1.2.4. 代码
    3. 1.3. chap9 管理良好的集合—迭代器与组合模式
      1. 1.3.1. 迭代器模式
        1. 1.3.1.1. 定义
        2. 1.3.1.2. 分析
        3. 1.3.1.3. UML
        4. 1.3.1.4. 代码
      2. 1.3.2. 组合模式
        1. 1.3.2.1. 定义
        2. 1.3.2.2. 分析
        3. 1.3.2.3. UML
        4. 1.3.2.4. 代码
    4. 1.4. chap10 事物的状态—状态模式
      1. 1.4.1. 定义
      2. 1.4.2. 分析
      3. 1.4.3. UML
      4. 1.4.4. 代码
    5. 1.5. chap11 控制对象访问—代理模式
      1. 1.5.1. 定义
      2. 1.5.2. 分析
      3. 1.5.3. UML
      4. 1.5.4. 代码
    6. 1.6. chap12 复合模式—模式的模式