(原創) 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)
在strategy pattern中,為了讓各strategy能方便存取原來物件的所有public member function,我們常用*this將整個物件傳給各strategy,這樣的設計並沒有什麼不好,但各strategy和原物件過於tight coupling,導致各strategy難以再和其他各物件搭配,本文使用template解決此問題。
在(原創) 我的Design Pattern之旅:Strategy Pattern (初級) (Design Pattern) (C++) (OO C++) (Template C++)中,我們使用了strategy pattern讓Grapher能畫Triangle、Circle和Square
因為需求再次改變,:D,我們希望Grapher能將文字印在各Shape中,執行結果如下
Draw Hello Shape!! in Square
Draw Hello C++!! in Circle
為了達到此需求,我們可以將IShape interface改成
class IShape {
public:
virtual void draw(const char *text) const = 0;
};
但若將來需求再改變,希望畫的不是文字,而是一張圖片,那interface又必須再變動,為了一勞永逸,我們會將整個物件傳給各strategy,IShape interface改成如下
class IShape {
public:
virtual void draw(Grapher &grapher) const = 0;
};
Grapher::drawShpae()將*this傳給各strategy
void drawShape() {
this->shape->draw(*this);
}
完整的程式碼如下

/* 2
(C) OOMusou 2007 http://oomusou.cnblogs.com3

4
Filename : DP_StrategyPattern3_polymorphism_this.cpp5
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++6
Description : Demo how to use Strategy Pattern with *this7
Release : 04/04/2007 1.08
*/9
#include <iostream>10
#include <string>11

12
using namespace std;13

14
class Grapher;15

16
class IShape {17
public:18
virtual void draw(Grapher &grapher) const = 0;19
};20

21
class Grapher {22
private:23
IShape *shape;24
string text;25

26
public:27
Grapher() {}28
Grapher(IShape *shape, const char *text = "Hello Shape!!") : shape(shape), text(string(text)) {}29
30
public:31
void drawShape() {32
this->shape->draw(*this);33
}34
35
void setShape(IShape *shape, const char* text = "Hello Shape!!") {36
this->text = text;37
this->shape = shape;38
} 39
40
string getText() const {41
return this->text;42
}43
};44

45

46
class Triangle : public IShape {47
public:48
void draw(Grapher &grapher) const {49
cout << "Draw " << grapher.getText() << " in Triangle" << endl;50
}51
};52

53
class Circle : public IShape {54
public:55
void draw(Grapher &grapher) const {56
cout << "Draw " << grapher.getText() << " in Circle" << endl;57
}58
};59

60
class Square : public IShape {61
public:62
void draw(Grapher &grapher) const {63
cout << "Draw " << grapher.getText() << " in Square" << endl;64
}65
};66

67

68
int main() {69
Grapher theGrapher(&Square());70
theGrapher.drawShape();71
72
theGrapher.setShape(&Circle(), "Hello C++!!");73
theGrapher.drawShape();74
}
執行結果
Draw Hello Shape!! in Square
Draw Hello C++!! in Circle
這樣的設計看似完美,但IShape和Grapher相依程度太高,若將來有個Painter class,和Grapher完全不同,沒有任何繼承或多型的關係,但想重複使用IShape interface的strategy,這樣的設計就無法讓Painter使用了。若我們能讓IShape interface的draw()不再只限定Grapher型別,改用template,就能讓將來所有型別都能使用IShape interface。
template <typename T>
class IShape {
public:
virtual void draw(T &grapher) const = 0;
};我們用泛型T取代了Grapher,任何型別都可傳進IShape::draw()。
完整程式碼如下

/* 2
(C) OOMusou 2007 http://oomusou.cnblogs.com3

4
Filename : DP_StrategyPattern3_template_this.cpp5
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++6
Description : Demo how to use Strategy Pattern with *this by template7
Release : 04/03/2007 1.08
*/9
#include <iostream>10
#include <string>11

12
using namespace std;13

14
class Grapher;15

16
template <typename T>17
class IShape {18
public:19
virtual void draw(T &grapher) const = 0;20
};21

22
class Grapher {23
private:24
IShape<Grapher> *shape;25
string text;26
27
public:28
Grapher() {}29
Grapher(IShape<Grapher> *shape, const char* text = "Hello Shape!!") : shape(shape), text(string(text)) {}30
31
public:32
void drawShape() {33
this->shape->draw(*this);34
}35
36
void setShape(IShape<Grapher> *shape, const char* text = "Hello Shape!!") {37
this->text = text;38
this->shape = shape;39
}40
41
string getText() const {42
return this->text;43
}44
};45

46
template <typename T>47
class Triangle : public IShape<T> {48
public:49
void draw(T &grapher) const {50
cout << "Draw " << grapher.getText() << " in Triangle" << endl;51
}52
};53

54
template <typename T>55
class Circle : public IShape<T> {56
public:57
void draw(T &grapher) const {58
cout << "Draw " << grapher.getText() << " in Circle" << endl;59
}60
};61

62
template <typename T>63
class Square : public IShape<T> {64
public:65
void draw(T &grapher) const {66
cout << "Draw " << grapher.getText() << " in Square" << endl;67
}68
};69

70

71
int main() {72
Grapher theGrapher(&Square<Grapher>());73
theGrapher.drawShape();74
75
theGrapher.setShape(&Circle<Grapher>(), "Hello C++!!");76
theGrapher.drawShape();77
}
執行結果
Draw Hello Shape!! in Square
Draw Hello C++!! in Circle
Conclusion
泛型的應用相當廣,在此範例僅僅是泛型的小小應用,在OOP世界使用strategy pattern,常將*this傳給strategy,若搭配GP可讓strategy pattern的resuse程度更高。
See Also
(原創) 我的Design Pattern之旅[1]:Strategy Pattern (初級) (Design Pattern) (C++) (OO C++) (Template C++)
(原創) 我的Design Pattern之旅[4]:使用Generic改進Strategy Pattern (高級) (Design Pattern) (C#) (Generic)


Grapher()
浙公网安备 33010602011771号