2009年12月11日 星期五

Bridge Patthern

昨天真是愉快(打混)的一天,因為欠上篇提到coding convention與link裡的Herder files dependencies讓我想起之前effective c++報告過的item 31 Minimize compilation dependencies between files。在大家討論的過程中,forward declaration 的精神相信大家都透過hsu的 abow-stara類別圖更了解了,現在來點實用的吧! Bridge Pattern。我小改了以前item31的sample(因為貼code篇幅還有天生的惰性,在Person端的implement有偷懶),總之,review以前的code再擴充些亂七八糟的想法真是太有趣了。


Bridge Pattern.bmp
把實際Implementor的部分跟Abstraction分開除了減低compiler的時間跟file dependency以外,還可以靈活的切換自己想要套用的實作方式,舉例來說,Abstraction(Person class)可能定義了說出姓名的name(),但是每個人都有”秘密”,甚麼時候用甚麼身分,可以透過Implementor(Personimpl)作切換。同樣的作法也很適合windows style或theme的實作,達到動態切換transparency 或其他想要的顯示方式。
Person.h
#ifndef _PERSON_H
#define _PERSON_H
                   
using namespace std;
//#include "Personimpl.h"
class Personimpl;                      // forward decl of Person impl. class
class Person {         // Person interface
public:
 
 Person(Personimpl& Pimpl);
 std::string name() const;
private:     
    Person();
    Person(const Person&);
       // ptr to implementation;
    Personimpl* pimpl;  // see Item 13 for info 
};                                         // std::tr1::shared_ptr
/////////////////////
#endif
Person.cpp
Person::Person(Personimpl& Pimpl
      ):pimpl(&Pimpl){
}

std::string Person::name() const
{
   return pimpl->name();              // very important !!
}

main可以這樣用它們
int main() {
std::string name;
Personimpl* ImplManager[3];

ImplManager[0] = NULL;
ImplManager[1] = new Workerimpl();
ImplManager[2] = new Playerimpl();
int pname;
pname=1;

while(pname != 0 ){
 
 printf("input your char, type 1:Worker :  2: Player  0: exit");
 cin>>pname;
 if(pname == 0) break;
 Person p(*ImplManager[pname]);
 printf(p.name().c_str());
}

    system("pause");
}
兩邊的implement分別是(這邊name()只是隨機的從name list挑一個print)。
#ifndef _WORKERIMPL_H
#define _WORKERIMPL_H
#include "stdafx.h"
#include 
#include "Personimpl.h"
using namespace std;

class Workerimpl : public Personimpl{
 public:
char* playerName[5];

 Workerimpl(//const std::string& name, const Date& birthday,        const Address& addr
  ){
  playerName[0] ="chen";
  playerName[1] ="hsin";
  playerName[2] ="brian";
  playerName[3] ="洨歪";
  playerName[4] ="Guru";
 };

 std::string name() const{  std::string str2(playerName[rand()%5]);  return str2;};

};    
#endif
/////////////////////////Playerimpl.h/////////////////////////////
class Playerimpl : public Personimpl{
private:
 vector ivector;
public:
 Playerimpl(){
 ivector.push_back("劍欠");
 ivector.push_back("abow");
 ivector.push_back("布萊劉");
 ivector.push_back("衝惹辣");
 ivector.push_back("上山打獵");

};
 std::string name() const {  return ivector[rand()%ivector.size()]; };
};    

都繼承同一個implementor
#ifndef _PERSONIMPL_H
#define _PERSONIMPL_H
#include "stdafx.h"
#include 
using namespace std;
class Personimpl{
public:
Personimpl(){};
 virtual std::string name() const = 0;
};    
#endif
最後順帶提,用vc2005實驗effective c++常很洩氣,因為某些觀念得不到驗證,像是昨天關於forward declaration的使用,不管我用的是include or forward declaration,得到的結果都是這樣…。
1>Skipping... (no relevant changes detected)
1>Person.cpp
好在最後NJ有在xcode幫忙double check. 推

4 則留言:

  1. 透過hsu的 abow-stara類別圖 !
    我也想看! (連Hsu參與討論,大驚!!!!,Hsu都針對我)

    回覆刪除
  2. 挑替一下~
    main可以這樣用它們的sample 會crash 吧?
    Personimpl* ImplManager[2]; ->只alloc 兩個
    但是
    ImplManager[0] = NULL;
    ImplManager[1] = new Workerimpl();
    ImplManager[2] = new Playerimpl();
    卻用到第三個去了

    回覆刪除
  3. 另外Bridge是屬於 Structural Patterns 這個category
    如果是針對"還可以靈活的切換自己想要套用的實作方式"這個需求的話,它應該是落在Behavioral Patterns這個category,裡面的Strategy Pattern跟這個例子很像。
    不過話說回來,Design Pattern不應該用得太死,也就是說不一定要一模一樣或非得說它是什麼Pattern,並且還可以整合運用。

    一點點想法供各位參考。
    Reference http://www.dofactory.com/Patterns/Patterns.aspx

    回覆刪除
  4. 我也想看abow-hsu類別圖~只是圍觀人太多我只好繼續寫exp. code.

    main可以這樣用它們的sample 會crash 吧?
    Thank you~ my reviewer

    回覆刪除