设计模式(二)

1.适配器模式

定义

将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。

其包含适配器类(根据客户的需求,将适配者已有的接口转换成另一个接口)、适配者类(适配器包装的对象)。

以下以“表白暗语翻译器”为例:

 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
#include <iostream>
#include <string>
#include <vector>

// 原有接口
class Target
{
public:
    virtual ~Target() = default;

    virtual std::string Answer() const
    {
        return "I love you\n";
    }
};

// 需要通过适配器处理的适配者
class Adaptee
{
public:
    std::vector<int> SpecialAnswer() const
    {
        return std::vector<int> {73,32,108,111,118,101,32,121,111,117};
    }
};

// 适配器,需要继承默认接口,可以处理适配者,便于使用
class Adapter:public Target
{
private:
    Adaptee *adaptee;

public:
    Adapter(Adaptee *adaptee) : adaptee(adaptee) {}
    // 实现对原有数据的解析
    std::string Answer() const override
    {
        std::vector<int> ciphertext = this->adaptee->SpecialAnswer();
        std::string cleartext;
        for(int i:ciphertext)
        {
            cleartext += char(i);
        }
        return cleartext;
    }
};

int main()
{
    Target *target = new Target;
    Adaptee *adaptee = new Adaptee;

    std::cout<<"Target mode:"<<std::endl;
    std::cout<<target->Answer();

    std::cout<<"Adaptee mode:"<<std::endl;
    Adapter *adapter = new Adapter(adaptee);
    std::cout<<adapter->Answer();
}

结果:

I Love you

I Love you

2.桥接模式

定义

将抽象部分与它的实现部分解耦,使得两者都能够独立变化。

具体来说,就是抽取其中一个维度并使之成为独立的类层次,这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。

桥接模式将两个独立变化的维度设计成两个独立的继承等级结构(而不会将两者耦合在一起形成多层继承结构),在抽象层将二者建立起一个抽象关联,该关联关系类似一座桥,将两个独立的等级结构连接起来。

其包含抽象类、实现类接口、扩充抽象类、具体实现类。

以下以“发行于Windows和Linux的不同游戏”为例:

 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
#include <iostream>
#include <string>
// 打个不恰当的比方,实现类相当于各式各样的软件,抽象类相当于各式各样的平台
// 实现类(接口)
class Game
{
public:
    Game() {}
    virtual void Play() const = 0;
    virtual ~Game() {}
};

// 具体实现类
class GameA : public Game
{
public:
    GameA() {}
    void Play() const override
    {
        std::cout << "Play Game A" << std::endl;
    }
};

// 具体实现类
class GameB : public Game
{
public:
    GameB() {}
    void Play() const override
    {
        std::cout << "Play Game B" << std::endl;
    }
};

// 抽象类
class OS
{
public:
    OS(){}
	virtual void SetupGame(Game *game) = 0;
	virtual void Play() = 0;
    virtual ~OS(){}
protected:
	Game *game;
};

// 扩充抽象类
class Windows:public OS
{
public:
    Windows(){}
    void SetupGame(Game *game) override
    {
        this->game = game;
    }
    void Play() override
    {
        std::cout<<"On Windows:";
        this->game->Play();
    }
};

// 扩充抽象类
class Linux:public OS
{
public:
    Linux(){}
    void SetupGame(Game *game) override
    {
        this->game = game;
    }
    void Play() override
    {
        std::cout<<"On Linux:";
        this->game->Play();
    }
};

int main()
{
    Game *game;
	OS *os;

    game = new GameA();
    os = new Windows();
    os->SetupGame(game);
    os->Play();

    game = new GameB();
    os = new Linux();
    os->SetupGame(game);
    os->Play();

    delete game;
    delete os;
}

结果:

On Windows:Play Game A On Linux:Play Game B

3.组合模式

组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。

由抽象构件(提供公共接口)、叶子构件、容器构件(既可包含容器构件、也可包含叶子构件)。

以下以“电脑中的文件管理系统”为例:

  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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <iostream>
#include <string>
#include <vector>
// 组合模式很像电脑中文件和文件夹的管理系统
// 抽象构件
class Component
{
public:
    Component() {}
    Component(std::string name)
    {
        this->name = name;
    }
    virtual ~Component(){}
    // 增加、移除叶子和容器组件的操作(此处为文件和文件夹)
    virtual void add(Component *){};
    virtual void remove(Component *){};
    virtual void getInfo() const = 0;
    std::string getName()
    {
        return name;
    }
    virtual int getSize()
    {
        return size;
    }

protected:
    std::string name;
    int size;
};

// 叶子构件。注意叶子构件不支持add和remove方法
class File : public Component
{
public:
    File() {}
    File(std::string name, int size)
    {
        this->name = name;
        this->size = size;
    }
    void getInfo() const override
    {
        std::cout << name << ':' << size << "KB" << std::endl;
    }
};

// 叶子构件的具体类
class CppFile : public File
{
public:
    CppFile(std::string name, int size)
    {
        this->name = name;
        this->size = size;
    }
};

// 叶子构件的具体类
class PythonFile : public File
{
public:
    PythonFile(std::string name, int size)
    {
        this->name = name;
        this->size = size;
    }
};

// 容器构件,利用了递归算法搜索容器内的每一个构件
class Dir : public Component
{
public:
    Dir(std::string name)
    {
        this->name = name;
        this->size = 0;
    }
    void add(Component *c) override
    {
        componentList.push_back(c);
        size += c->getSize();
    }
    void remove(Component *c) override
    {
        for (int i = 0; i < componentList.size(); i++)
        {
            if (componentList[i]->getName() == c->getName())
            {
                componentList.erase(componentList.begin() + i);
                size -= c->getSize();
                break;
            }
        }
    }
    // 遍历每一个组件的长度
    int getSize() override
    {
        int subsize = 0;
        for (int i = 0; i < componentList.size(); i++)
        {
            subsize += componentList[i]->getSize();
        }
        return subsize;
    }
    // 注意,允许递归搜索
    void getInfo() const override
    {
        std::cout << name << ':' << size << "KB" << std::endl;
        for (int i = 0; i < componentList.size(); i++)
        {
            ((Component *)componentList[i])->getInfo();
        }
    }

private:
    std::vector<Component *> componentList;
};

int main()
{
    Component *root;
    Component *Dir1, *Dir2, *Dir3;
    Component *File1, *File2, *File3, *File4, *File5, *File6, *File7;

    root = new Dir("root");
    Dir1 = new Dir("CppFiles");
    Dir2 = new Dir("PythonFiles");
    Dir3 = new Dir("CppProject");
    File1 = new File("test1.py", 2);
    File2 = new File("test2.py", 10);
    File3 = new File("test3.py", 3);
    File4 = new File("test1.cpp", 2);
    File5 = new File("test2.cpp", 1);
    File6 = new File("source.h", 1);
    File7 = new File("source.cpp", 4);

    Dir3->add(File6);
    Dir3->add(File7);
    Dir1->add(Dir3);
    Dir1->add(File4);
    Dir1->add(File5);
    Dir2->add(File1);
    Dir2->add(File2);
    Dir2->add(File3);
    Dir2->remove(File3);
    root->add(Dir1);
    root->add(Dir2);
    root->add(Dir3);

    root->getInfo();

    delete root;
    delete Dir1;
    delete Dir2;
    delete Dir3;
    delete File1;
    delete File2;
    delete File3;
    delete File4;
    delete File5;
    delete File6;
    delete File7;
}

结果:

root:25KB CppFiles:8KB CppProject:5KB source.h:1KB source.cpp:4KB test1.cpp:2KB test2.cpp:1KB PythonFiles:12KB test1.py:2KB test2.py:10KB CppProject:5KB source.h:1KB source.cpp:4KB

4.装饰模式

定义

动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。

装饰模式是一种用于替代继承的技术。通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。

由抽象构件、具体构件、抽象装饰类、具体装饰类组成。

以下以“穿不同衣服的人”为例:

 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<iostream>
#include<string>

// 抽象构件类,它是具体构件类和抽象装饰类的共同基类
class Component
{
public:
    Component() {}
    virtual void Operation() const = 0;
    virtual ~Component() {}
};

// 具体构件类
class Person:public Component
{
public:
    Person(std::string name)
    {
        this->name = name;
    }
    void Operation()const override
    {
        std::cout<<name<<std::endl;
    }

private:
    std::string name;
};

// 抽象装饰类。注意Decorator必须继承Component,这样才能实现连续装饰
class Decorator:public Component
{
public:
    Decorator(){};
    Decorator(Component *c)
    {
		this->component = c;
	}
protected:
    // 被装饰的对象
	Component *component;
};

// 具体装饰类
class Shirt:public Decorator
{
public:
    Shirt(Component *c)
    {
        this->component = c;
    }
    void Operation()const override
    {
        component->Operation();
        std::cout<<"wear a shirt"<<std::endl;
    }
};

// 具体装饰类
class Pants:public Decorator
{
public:
    Pants(Component *c)
    {
        this->component = c;
    }
    void Operation()const override
    {
        component->Operation();
        std::cout<<"wear pants"<<std::endl;
    }
};

int main()
{
    Component *c;
    Component *shirt;
    Component *pants;

    // 注意添加装饰的过程
    c= new Person("Alice");
    shirt = new Shirt(c);
    shirt->Operation();
    std::cout<<std::endl;
    pants = new Pants(shirt);
    pants->Operation();

    delete c;
    delete shirt;
    delete pants;
}

结果:

Alice wear a shirt

Alice wear a shirt wear pants

5.外观模式

定义

为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

引入了外观类,原有的复杂的引用关系都由外观类实现,不同的客户端只需要与外观类交互。

内含外观角色和子系统角色。

以下以“Vscode中的编辑器和终端操作”为例:

 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
#include<iostream>
#include<string>

// 在进入和退出Vscode时,我们不需要了解其内部逻辑,只需要按下按钮与GUI进行交互
// 子系统
class TextEditor
{
public:
    TextEditor(){}
    void open()
    {
        std::cout<<"open the text editor"<<std::endl;
    }
    void close()
    {
        std::cout<<"close the text editor"<<std::endl;
    }
};

// 子系统
class Terminal
{
public:
    Terminal(){}
    void open()
    {
        std::cout<<"open the terminal"<<std::endl;
    }
    void close()
    {
        std::cout<<"close the terminal"<<std::endl;
    }
};

// 外观系统,使用者通过调用外观系统与子系统进行交互
class Facade
{
public:
    Facade ()
    {
        textEditor = new TextEditor();
        terminal = new Terminal();
    }
    ~Facade ()
    {
        delete textEditor;
        delete terminal;
    }
    void open()
    {
        textEditor->open();
        terminal->open();
    }
    void close()
    {
        textEditor->close();
        terminal->close();
    }
private:
    TextEditor* textEditor;
    Terminal* terminal;
};

int main()
{
    Facade *facade;
    facade = new Facade();
    facade->open();
    facade->close();
    delete facade;
}

结果:

open the text editor open the terminal close the text editor close the terminal

6.享元模式

运用共享技术有效地支持大量细粒度对象的复用。

享元模式通过共享技术实现相同或相似的细粒度对象的复用,提供一个享元池存储已经创建好的对象,并通过享元工厂类将享元对象提供给客户端使用。

可分为抽象享元类、具体享元类、非共享享元类和享元工厂类。

以下以“连接路由器和以太网的电脑”为例:

 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
#include<iostream>
#include<string>
#include<vector>

// 抽象享元类
class Device
{
public:
    Device(){}
    virtual ~Device(){}
    virtual std::string getName() = 0;
};

// 具体享元类
class Ethernet:public Device
{
public:
    Ethernet(){}
    std::string getName() override
    {
        return "Ethernet ";
    }
};

// 具体享元类
class Router:public Device
{
public:
    Router(){}
    std::string getName() override
    {
        return "Router ";
    }
};

// 享元工厂,这里利用了单例模式
class Factory
{
public:
    Device* getDevice(char ch)
    {
        if (ch == 'E')
        {
            return devicePool[0];
        }
        else if(ch == 'R')
        {
            return devicePool[1];
        }
        return nullptr;
    }

    // 单例模式的应用
    static Factory* getFactory()
    {
        if (instance == nullptr)
        {
            instance = new Factory();
        }
        return instance;
    }

private:
    Factory ()
    {
        Ethernet *ethernet = new Ethernet();
        Router *router = new Router();
        devicePool.push_back(ethernet);
        devicePool.push_back(router);
    }
    static Factory* instance;
    std::vector<Device*> devicePool;
};

Factory* Factory::instance = nullptr;

int main()
{
    Factory *factory = Factory::getFactory();
    Device *device1,*device2,*device3,*device4;
    device1 = factory->getDevice('E');
    std::cout<<device1->getName()<<device1<<std::endl;

    device2 = factory->getDevice('E');
    std::cout<<device2->getName()<<device2<<std::endl;

    device3 = factory->getDevice('R');
    std::cout<<device3->getName()<<device3<<std::endl;

    device4 = factory->getDevice('R');
    std::cout<<device4->getName()<<device4<<std::endl;

    delete device1;
    delete device3;
    delete factory;
}

结果:

7.代理模式

定义

给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

代理对象可以屏蔽或删除客户不想访问的内容和服务,也可以根据客户需求增加新的内容和服务。

可分为抽象主题、真实主题和代理主题。

以下以“使用代理‘科学上网’”为例:

 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
#include<iostream>
#include<string>
#include<vector>

// 抽象主题角色
class Subject
{
public:
    Subject(){}
    virtual void method() = 0;
    virtual ~Subject(){}
};

// 具体主题角色
class RealSubject:public Subject
{
public:
    RealSubject()
    {
    }
    void method() override
    {
        std::cout<<"Log in success!"<<std::endl;
    }
};

// 代理角色
class Proxy:public Subject
{
public:
    Proxy ()
    {
        realSubject = new RealSubject();
    }
    void method() override
    {
        std::cout<<"using Proxy..."<<std::endl;
        realSubject->method();
    }
    ~Proxy () override
    {
        delete realSubject;
    }
private:
    RealSubject *realSubject;
};

int main()
{
    Subject *subject;
    subject = new RealSubject();
    subject->method();

    std::cout<<std::endl;
    subject = new Proxy();
    subject->method();

    delete subject;
}

结果:

Log in success!

using Proxy… Log in success!

Built with Hugo
Theme Stack designed by Jimmy
visitors: total visits: time(s) reads: time(s)