(原創) 我的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);
}


完整的程式碼如下


 1/* 
 2(C) OOMusou 2007 http://oomusou.cnblogs.com
 3
 4Filename    : DP_StrategyPattern3_polymorphism_this.cpp
 5Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 6Description : Demo how to use Strategy Pattern with *this
 7Release     : 04/04/2007 1.0
 8*/

 9#include <iostream>
10#include <string>
11
12using namespace std;
13
14class Grapher;
15
16class IShape {
17public:
18  virtual void draw(Grapher &grapher) const = 0;
19}
;
20
21class Grapher  {
22private:
23  IShape *shape;
24  string text;
25
26public:
27  Grapher() {}
28  Grapher(IShape *shape, const char *text = "Hello Shape!!") : shape(shape), text(string(text)) {}
29  
30public:
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
46class Triangle : public IShape {
47public:
48  void draw(Grapher &grapher) const {
49    cout << "Draw " << grapher.getText() << " in Triangle" << endl;
50  }

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

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

65}
;
66
67
68int 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()。

完整程式碼如下

 1/* 
 2(C) OOMusou 2007 http://oomusou.cnblogs.com
 3
 4Filename    : DP_StrategyPattern3_template_this.cpp
 5Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 6Description : Demo how to use Strategy Pattern with *this by template
 7Release     : 04/03/2007 1.0
 8*/

 9#include <iostream>
10#include <string>
11
12using namespace std;
13
14class Grapher;
15
16template <typename T>
17class IShape {
18public:
19  virtual void draw(T &grapher) const = 0;
20}
;
21
22class Grapher {
23private:
24  IShape<Grapher> *shape;
25  string text;
26    
27public:
28  Grapher() {}
29  Grapher(IShape<Grapher> *shape, const char* text = "Hello Shape!!") : shape(shape), text(string(text)) {}
30  
31public:
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
46template <typename T>
47class Triangle : public IShape<T> {
48public:
49  void draw(T &grapher) const {
50    cout << "Draw " << grapher.getText() << " in Triangle" << endl;
51  }

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

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

68}
;
69
70
71int 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)

posted on 2007-04-06 22:06 真 OO无双 阅读(...) 评论(...) 编辑 收藏

Powered by .NET Core 3.0 Preview 8 on Linux

导航

统计