在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)

(原創) 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)...相关推荐

  1. (原創) 如何破解ModelSim 6.1f? (IC Design) (ModelSim)

    Abstract本文介紹如何破解ModelSim 6.1f. Introduction Step 1: 直行setup.exe安裝ModelSim. Step 2: 選擇Full Product St ...

  2. (原創) 如何讀取/寫入文字檔? (IC Design) (Verilog)

    Abstract Verilog雖然為硬體描述語言,亦提供讀取/寫入文字檔的功能. Introduction為什麼需要用Verilog讀取/寫入文字檔呢?主要用在寫Testbench,並且有兩個優點: ...

  3. (原創) 如何將CMOS所擷取的影像傳到PC端? (SOC) (DE2) (TRDB-DC2)

    AbstractDE2提供了Control Panel與Image Converter,可以將CMOS所擷取的影像傳到PC端, Introduction 版權聲明:文中所有範例皆出自DE2光碟,版權歸 ...

  4. (原創) Verilog入門書推薦2:數位系統實習 Quartus II (SOC) (Verilog)

    Abstract 之前曾經推薦過一本Verilog的薄書,這次再推薦一本適合FPGA與Quartus II的Verilog入門書籍. Intrduction 作者:陸自強 出版社:儒林圖書公司 語言: ...

  5. (原創) 如何使用ModelSim-Altera對Nios II仿真? (SOC) (Nios II) (SOPC Builder) (ModelSim) (DE2)...

    Abstract 在剛學習Nios II時,每次在Run As Nios II Hardware下方,看到Run As Nios II ModelSim就覺得很好奇,Nios II明明是嵌入式系統,怎 ...

  6. (原創) 如何解決DE2_LCM_CCD上下顛倒左右相反與無法設定曝光值的問題? (SOC) (DE2)...

    AbstractDE2_LCM_CCD是友晶科技為DE2和其130萬像素CMOS與彩色LCD所寫的範例,但官方的範例會造成上下顛倒左右相反與曝光值無法設定的問題,本文提出解決方式. Introduct ...

  7. (原創) 如何將DE2_70_TV範例加上Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70)...

    Abstract 本文將DE2-70平台的DE2_70_TV的範例加上Sobel Edge Detector. Introduction 使用環境:Quartus II 8.0 + DE2-70 (C ...

  8. (原創) ThinkPad X61安裝過程全紀錄 (NB) (ThinkPad) (X61)

    Abstract 我的ThinkPad X61安裝過程詳細紀錄. Introduction Step 1: ThinkPad X61基本硬體 (原創) 如何自行在ThinkPad X61安裝Windo ...

  9. (原創) 如何使用SignalTap II觀察reg與wire值? (SOC) (Verilog) (Quartus II) (SignalTap II)

    Abstract 撰寫Verilog時,雖然每個module都會先用ModelSim或Quartus II自帶的simulator仿真過,但真的將每個module合併時,一些不可預期的『run-tim ...

最新文章

  1. ajax invoke error,配置全局的异常捕获时,走ajax请求下面报错
  2. python自学笔记(三)python基本数据类型之列表list
  3. 关于模型复杂度的一个想法
  4. Hive记录-配置远程连接(JAVA/beeline)
  5. WebView 加载javaScript
  6. java 同步块 抛出异常_java问题合集(一)
  7. 分布式事务seate-server的docker镜像的制作与部署
  8. 7天拿到阿里安卓岗位offer,附高频面试题合集
  9. 计算机组成原理写一个运算器,计算机组成原理运算器的实现实验报告.doc
  10. Java堆分配参数总结
  11. malloc分配的内存空间是连续的吗
  12. 利用vs 分析DMP文件、pdb文件定位release下的异常崩溃
  13. java怎么缓存数据_java中的缓存技术该如何实现
  14. mosek安装及出现的问题解决方法
  15. 计算机丢失mscvr,教大家计算机丢失Msvcr100.dll的解决方法
  16. 教师心理压力测试软件,关注教师心理健康——教师版心理测评软件
  17. Java资深开发:这不得40k起步呀
  18. Windows 11如何使用IE浏览器
  19. Java生成指定范围的随机数
  20. 码云(gitee)的使用

热门文章

  1. 案例分享|突破卡脖子技术,研制协作机器人核心零部件的方向与思考
  2. 物理理论发展放缓?这是一种认知误判
  3. 申工智能有没有作弊?
  4. 人类正在进入超级智能时代,论一种新超级智能的崛起
  5. 智能硬件这5大领域竞争升级,将迎发展新模式
  6. 深度学习在推荐系统上的应用
  7. 任正非最新讲话透露:华为在加快开发统一的人工智能平台
  8. “32 位应用已死!”
  9. react-router中离开确认组件Prompt
  10. dubbo服务发布一之服务暴露