1. 程式人生 > 實用技巧 >C++ 設計模式--模板模式、策略模式、觀察者模式

C++ 設計模式--模板模式、策略模式、觀察者模式

現代軟體設計特徵:需求頻繁變化

設計模式的要點是“尋找變化點”,在變化點應用設計模式,從而更好的應對需求變化。

1、 Template Method

在軟體構建結構中,往往他有整體的穩定結構,但是各個子步驟確有變化的需求,或者因為固有的原因(比如框架和應用之間)而無法和任務的整體結構同時實現。
這個時候往往使用Template Method方法。

定義一個操作中演算法的骨架(穩定),而將一些步驟延遲(變化)到子類(父類定義虛擬函式,在子類中具體實現)。使得子類可以不改變(複用)一個演算法的結構即

可重定義override該演算法的某些特定步驟。讓框架呼叫應用程式而不是應用程式呼叫框架。“不要呼叫我讓我來呼叫你”,晚繫結和早繫結的區別。

UML類圖:

程式碼例項:


class Library {//穩定的資料結構,不會發生改變
  public:
    void step1() {}
    int step2() { return contrl;}
    void virtual step3() {}
    void step4() {}
    void virtual step5() {}
    
    void run() {
      step1();
      if(step2()) {
        step3();
      }   
      else {
        step5();
      }   

      for(int i = 10; i < 100; ++i) {
        step4();
      }   
    }   
    
    virtual ~Library() {}; 

    std::string name = "myname";
};

class Application1 : public Library {//  承載著不斷變化的需求
  public:
    void step3() override { std::cout << this->name << std::endl; }
    void step5() override { std::cout << this->Library::name << std::endl; }
    std:: string name = "Application";
};

class Application2 : public Library {//  承載者不斷變化的需求
  public:
    void step3() override {}
    void step5() override {}
}; 

 
int main() {
 Library *a = new Application1;
 a->run();
 delete a;
  return 0;
}
    

2、 策略模式(Strategy)

在軟體構建的過程中,某些物件使用的演算法可能多種多樣,經常改變,如果將這些演算法都編碼到物件中去,將會使得物件變得異常複雜,而且有時候支援幾乎不使用的演算法也是一種效能負擔。

問題:如何在執行的時候根據需要透明的改變演算法? 將演算法與物件本身解耦合,從而避免上述問題?
定義:定義一系列演算法,將他們一個個封裝起來,而且他們可以相互替換(變化)。該模式使得演算法可以獨立於使用他們的應用程式(穩定)而變化(擴張,子類化)

UML類圖:

程式碼例項:

class Strategy {
public:
  virtual int doOperation(int num1, int num2) {} // 基類中需要改寫的方法
  virtual ~Strategy(){}
};

class plus final : public Strategy {// 不同的策略
public:
  int doOperation(int num1, int num2) {
    return num1 + num2;
  }
};

class multipl final : public Strategy {
public:
  int doOperation(int num1, int num2) {
    return num1 * num2;
  }
};

class minus final : public Strategy {
public:
  int doOperation(int num1, int num2) {
    return num1 - num2;
  }
};

class Context { //封裝呼叫介面
public:
  Context(Strategy *init) :stra(init) {}
  int run(int num1, int num2) {
    return this->stra->doOperation(num1, num2);
  }
private:
  Strategy *stra;
};

 
int main() {
Context demo(new multipl);
std::cout << demo.run(10, 20) << std::endl; //使用呼叫介面中的基類指標多型的執行。
  return 0;
}

3、 觀察者模式(Observer)

一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的物件中使它們可以各自獨立地改變和複用。
一個物件的改變將導致其他一個或多個物件也發生改變,而不知道具體有多少物件將發生改變,可以降低物件之間的耦合度。
一個物件必須通知其他物件,而並不知道這些物件是誰。

定義:定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。

UML類圖:

程式碼示例:

enum class msg {
  RETURN1,
  RETURN2,
  RETURN3
};

class Observer {
  public:
    void virtual update(msg ms) = 0;
};

class ob1 : public Observer {
  public:
    void update(msg ms) {
      switch(ms) {
        case msg::RETURN1 :
        case msg::RETURN2 :
        case msg::RETURN3 :
          std::cout << "RETURN1" << std::endl;
        default:
          std::cout << "right" << std::endl;
      }
    }
};

class ob2 : public Observer {
  public:
    void update(msg ms) {
      switch(ms) {
        case msg::RETURN1 :
        case msg::RETURN2 :
        case msg::RETURN3 : {
          std::cout << "RETURN2" << std::endl;
          break;
        }
        default:
          std::cout << "erro ms2" << std::endl;
      }
    }
};

class ob3 : public Observer {
  public:
    void update(msg ms) {
      switch(ms) {
        case msg::RETURN1 :
        case msg::RETURN2 :
        case msg::RETURN3 : {
            std::cout << "RETURN3" << std::endl;
            break;
          }
        default:
          std::cout << "erro ms3" << std::endl;
      }
    }
};

class subject {
  public:
    void addob(Observer *ob) { obs.insert(ob);}
    void removeob(Observer *ob) {
      auto rob = obs.find(ob);
      if(rob != obs.end()){
        obs.erase(ob);
      }
      else std::cout << "erro no matching observer" << std::endl;
    }
    void update() {
      for(auto& ob : obs) {
        ob->update(ms);
      }
    }

    msg ms;
    std::set<Observer*> obs;
};

int main() {
 Observer *ob_1 = new ob1;
 Observer *ob_2 = new ob2;
 Observer *ob_3 = new ob3;
 subject *sub = new subject;
 sub->ms = msg::RETURN1;
 sub->addob(ob_1);
 sub->addob(ob_2);
 sub->addob(ob_3);
 sub->update();
 return 0;
}


observer:變化儘量通過呼叫方的多型機制,傳遞給被呼叫方,決定如何呼叫。