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:變化盡量通過調用方的多態機制,傳遞給被調用方,決定如何調用。