我的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
 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)
因為需求再次改變,: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);
}


完整的程式碼如下

 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)
 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
12 using   namespace  std;
13
14 class  Grapher;
15
16 class  IShape  {
17public:
18  virtual void draw(Grapher &grapher) const = 0;
19}
;
20
21 class  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
46 class  Triangle :  public  IShape  {
47public:
48  void draw(Grapher &grapher) const {
49    cout << "Draw " << grapher.getText() << " in Triangle" << endl;
50  }

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

58}
;
59
60 class  Square :  public  IShape  {
61public:
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()。

完整程式碼如下
 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)
 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
12 using   namespace  std;
13
14 class  Grapher;
15
16 template  < typename T >
17 class  IShape  {
18public:
19  virtual void draw(T &grapher) const = 0;
20}
;
21
22 class  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
46 template  < typename T >
47 class  Triangle :  public  IShape < T >   {
48public:
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 >   {
56public:
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 >   {
64public:
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)

你可能感兴趣的:(design pattern)