Contents

设计模式总结四

这一部分总结一下行为型设计模式中的5个,分别是:中介者模式、访问者模式、策略模式、备忘录模式、迭代器模式

4.1 中介者模式 (Mediator)

特点

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

应用场景

  • a.一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解

  • b.想定制一个分布在多个类中的行为,而又不想生成太多子类

UML图

/images/design_pattern4_1.png

实现

 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
// 中介者模式
class Country;
class UnitedNations
{
public:
    virtual void Declare(string message, Country *colleague) = 0;
};

class Country
{
public:
    Country(UnitedNations *mediator)
        :mediator_(mediator)
    {
    }
protected:
    UnitedNations *mediator_;
};

class USA: public Country
{
public:
    USA(UnitedNations *mediator)
        :Country(mediator)
    {}
    void Declare(string message)
    {
        mediator_->Declare(message, this);
    }
    void GetMessage(string message)
    {
        std::cout << "USA get message from others: " << message << std::endl;
    }
};

class Iraq: Country
{
public:
    Iraq(UnitedNations *mediator)
        :Country(mediator)
    {}
    void Declare(string message)
    {
        mediator_->Declare(message, this);
    }
    void GetMessage(string message)
    {
        std::cout << "Iraq get message form others: " << message << std::endl;
    }
};

class UnitedNationsSecurityCouncil: public UnitedNations
{
public:
    void SetColleague1(USA *colleague)
    {
        colleague1_ = colleague;
    }
    void SetColleague2(Iraq *colleague)
    {
        colleague2_ = colleague;
    }
    virtual void Declare(string message, Country *colleague) override
    {
        if (colleague == colleague1_)
        {
            colleague2_->GetMessage(message);
        }
        else
        {
            colleague1_->GetMessage(message);
        }
    }
private:
    USA *colleague1_;
    Iraq *colleague2_;
};

int main()
{
    UnitedNationsSecurityCouncil *UNSC = new UnitedNationsSecurityCouncil();
    USA *c1 = new USA(UNSC);
    Iraq *c2 = new Iraq(UNSC);
    UNSC->SetColleague1(c1);
    UNSC->SetColleague2(c2);
    c1->Declare("dont do A action");
    c2->Declare("we did not do that");
    delete UNSC;
    delete c1;
    delete c2;
    return 0;
}

/*
output:
Iraq get message form others: dont do A action
USA get message from others: we did not do that
*/

优点

  • a.减少了子类的生成
  • b.简化了对象协议
  • c.对对象如何协作进行了抽象

缺点

  • a.使控制集中化,于是就把交互复杂性变为了中介者的复杂性

4.2 访问者模式 (Visitor)

特点

表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

应用场景

  • a.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作

  • b.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免这些操作“污染”这些对象的类

  • c.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作

UML图

/images/design_pattern4_2.png

实现

  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
// 访问者模式
class ConcreteElementA;
class ConcreteElementB;
class Visitor
{
public:
    virtual void VisitConcreteElementA(ConcreteElementA *a) = 0;
    virtual void VisitConcreteElementB(ConcreteElementB *a) = 0;
protected:
    string name_;
};
class Element
{
public:
    virtual void Accept(Visitor *visitor) = 0;
    string name_;
};

class ConcreteElementA:public Element
{
public:
    ConcreteElementA()
    {
         name_ = "ConcreteElementA";
    }
    void Accept(Visitor *visitor)
    {
        visitor->VisitConcreteElementA(this);
        OperationA();
    }
    void OperationA()
    {
        std::cout << "OperationA" << std::endl;
    }
};
class ConcreteElementB:public Element
{
public:
    ConcreteElementB()
    {
        name_ = "ConcreteElementB";
    }
    void Accept(Visitor *visitor)
    {
        visitor->VisitConcreteElementB(this);
        OperationB();
    }
    void OperationB()
    {
        std::cout << "OperationB" << std::endl;
    }
};

class ConcreteVisitor1: public Visitor
{
public:
    ConcreteVisitor1()
    {
        name_ = "ConcreteVisitor1";
    }
    virtual void VisitConcreteElementA(ConcreteElementA *concreteA) override
    {
        std::cout << concreteA->name_ << " visit " << "ConcreteVisitor1" << std::endl;
    }
    virtual void VisitConcreteElementB(ConcreteElementB *concreteB) override
    {
        std::cout << concreteB->name_ << " visit " << "ConcreteVisitor1" << std::endl;
    }
};
class ConcreteVisitor2: public Visitor
{
public:
    ConcreteVisitor2()
    {
        name_ = "ConcreteVisitor2";
    }
    virtual void VisitConcreteElementA(ConcreteElementA *concreteA) override
    {
        std::cout << concreteA->name_ << " visit " << "ConcreteVisitor2" << std::endl;
    }
    virtual void VisitConcreteElementB(ConcreteElementB *concreteB) override
    {
        std::cout << concreteB->name_ << " visit " << "ConcreteVisitor2" << std::endl;
    }
};

class ObjectStructure
{
public:
    void Attach(Element *eleteme)
    {
        list_.push_back(eleteme);
    }
    void Detach(Element *element)
    {
        for(auto it = list_.begin(); it != list_.end(); it++)
        {
            if (*it == element)
            {
                list_.erase(it);
            }
        }
    }
    void Accept(Visitor *visitor)
    {
        for(auto it = list_.begin(); it != list_.end(); it ++)
        {
            (*it)->Accept(visitor);
        }
    }
private:
    vector<Element*> list_;
};
int main()
{
    ObjectStructure *o = new ObjectStructure();
    ConcreteElementA *ea = new ConcreteElementA();
    ConcreteElementB *eb = new ConcreteElementB();
    o->Attach(ea);
    o->Attach(eb);
    ConcreteVisitor1 *v1 = new ConcreteVisitor1();
    ConcreteVisitor2 *v2 = new ConcreteVisitor2();
    o->Accept(v1);
    o->Accept(v2);
    delete v1;
    delete v2;
    delete ea;
    delete eb;
    delete o;
}
/*
output:
ConcreteElementA visit ConcreteVisitor1
OperationA
ConcreteElementB visit ConcreteVisitor1
OperationB
ConcreteElementA visit ConcreteVisitor2
OperationA
ConcreteElementB visit ConcreteVisitor2
OperationB
*/

优点

  • a.易于增加新的操作
  • b.集中了相关的操作而分离了无关的操作

缺点

  • a.增加新的数据结构比较困难

4.3 策略模式 (Strategy)

特点

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化

应用场景

  • a.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法

  • b.需要使用一个算法的不同变体

  • c.算法使用客户不应该知道的数据

  • d.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现

UML图

/images/design_pattern4_3.png

实现

 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
//策略模式
class CashSuper
{
public:
    virtual double AcceptCash(double money) = 0;
};
class CashContext
{
public:
    CashContext(CashSuper *cspuer)
    {
        cs_ =  cspuer;
    }
    void GetResult(double money)
    {
        double ret = cs_->AcceptCash(money);
        std::cout << " total money: " << ret << std::endl;
    }
private:
    CashSuper *cs_;
};
class CashNormal:public CashSuper
{
public:
    virtual double AcceptCash(double money)
    {
        std::cout << "Normal  ";
        return money;
    }
};
class CashRebate:public CashSuper
{
public:
    virtual double AcceptCash(double money)
    {
        double real_money = money * 0.8; 
        std::cout << "return: " << real_money;
        return real_money;
    }
};
class CashReturn:public CashSuper
{
public:
    virtual double AcceptCash(double money)
    {
         std::cout << "rebate money: " << int(money/3);
         return money;
    }
};

int main()
{
    CashContext *cs = nullptr;
    CashNormal *n = new CashNormal();
    CashRebate *rb = new CashRebate();
    CashReturn *rt = new CashReturn();
    cs = new CashContext(n);
    cs->GetResult(600);
    delete cs;
    delete n;

    cs = new CashContext(rb);
    cs->GetResult(600);
    delete cs;
    delete rb;

    cs = new CashContext(rt);
    cs->GetResult(600);
    delete cs;
    delete rt;    
}
/*
output:
Normal   total money: 600
return: 480 total money: 480
rebate money: 200 total money: 600
*/

优点

  • a.一个替代继承的方法

  • b.消除了一些条件语句

  • c.策略模式可以提供相同行为的不同实现

  • d.

缺点

  • a.使用的客户必须了解不同的策略

  • b.Strategy和Context之间的通信开销

  • d.增加了对象的数目

4.4 备忘录模式 (Memento)

特点

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后可将该对象恢复到原先保存的状态

应用场景

  • a.必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态

  • b.如果用一个接口让其他对象直接得到这些状态,将会暴露对象的实现细节并破环对象的封装性

UML图

/images/design_pattern4_4.png

实现

 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
// 备忘录模式
class Memento
{
public:
    Memento(string state)
        :state_(state)
    {}
    string GetState()
    {
        return state_;
    }
private:
    string state_;
};
// 发起人
class Originator
{
public:
    void SetState(string state)
    {
        state_ = state;
    }
    string GetState()
    {
        return state_;
    }
    Memento* CreateMemento()
    {
        return (new Memento(state_));
    }
    void SetMemento(Memento *memento)
    {
        state_ = memento->GetState();
    }
    void Show()
    {
        std::cout << "State= " << state_ << std::endl;
    }
private:
    string state_;
};
// 管理类
class Caretaker
{
public:
    Memento *memento; 
};
int main()
{
    Originator *o = new Originator();
    o->SetState("On");
    o->Show();

    Caretaker *c = new Caretaker();
    c->memento = o->CreateMemento();
    o->SetState("Off");
    o->Show();

    o->SetMemento(c->memento);
    o->Show();

    delete c->memento;
    delete c;
    delete o;
    return 0;
}
/*
output:
State= On
State= Off
State= On
*/

优点

  • a.保持封装的边界。把复杂的对象内部信息对其他的对象屏蔽起来

  • b.简化了Originator的设计

缺点

  • a.代价可能会很高。如果Originator在生成备忘录时必须拷贝并储存大量信息或者客户频繁创建备忘录和恢复Originator的状态,可能会导致非常大的开销

  • b.在一些语言中可能难以保证只有Originator可以访问备忘录的状态

  • c.维护备忘录的潜在代价可能会很大

4.5 迭代器模式 (Iterator)

特点

提供一种方法顺序访问一个聚合对象中各个元素,而不需要暴露该对象的内部表示

应用场景

  • a.访问一个聚合对象的内容而无需暴露它的内部表示

  • b.支持对聚合对象的多种遍历

  • c.为遍历不同的聚合结构提供一个统一的接口

UML图

/images/design_pattern4_5.png

实现

  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
// 迭代器模式
class Object
{
public:
    Object(string name="object")
        :name_(name)
    {
    }
    virtual string ToStirng()
    {
        return name_;
    };
private:
    string name_;
};
template<typename T>
class List
{

};
// 迭代器抽象类
template<typename T>
class Iterator
{
public:
    virtual void First() = 0;
    virtual void Next() = 0;
    virtual T CurrentItem() = 0;
    virtual bool IsDone() = 0;
};
// 具体的聚集类
template<typename T>
class ConcreteAggregate
{
public:
    ConcreteAggregate(size_t size = 64)
        :capcity_(size),current_(0),size_(0)
    {
        list_ = new T[size];
    }
    ~ConcreteAggregate()
    {
        delete[] list_;
    }
    size_t Count() const
    {
        return size_;
    }
    T& Get(size_t index) const
    {
        return list_[index];
    }
    void Set(size_t index, T value)
    {
        if (index >= size_)
        {
            size_ = index + 1;
        }
        list_[index] = value;
    }
private:
    T *list_;
    size_t capcity_;
    size_t current_;
    size_t size_;
};
template<typename T>
class ConcreteIterator: public Iterator<T>
{
public: 
    ConcreteIterator(const ConcreteAggregate<T> *list)
        :list_(list), current_(0)
    {}
    virtual void First() override
    {
        current_ = 0;
    }
    virtual void Next() override
    {
        current_++;
    }
    virtual bool IsDone() override
    {
        return (current_ >= list_->Count());
    }
    virtual T CurrentItem()
    {
        return list_->Get(current_);
    }
private:    
    const ConcreteAggregate<T> *list_;
    size_t current_;
};
int main()
{
    ConcreteAggregate<Object> *a = new ConcreteAggregate<Object>();
    string strs[3] = {"zhangsan", "lisi", "wangwu"};
    for(int i = 0; i < 3; i++)
    {
        a->Set(i, strs[i]);
    }
    
    ConcreteIterator<Object> forword(a);
    for(forword.First(); !forword.IsDone(); forword.Next())
    {
        std::cout << "name: " << forword.CurrentItem().ToStirng() << std::endl;
    }
    delete a;
    return 0;
}
/*
output:
name: zhangsan
name: lisi
name: wangwu
*/

优点

  • a.它支持以不同的方法遍历一个聚合

  • b.简化了聚合类的接口

  • c.在同一个聚合类上可以有多个遍历

缺点