Design Pattern 小筆記
¶Design Pattern 小筆記
原文連結: https://darkblack01.blogspot.com/2013/12/design-pattern.html
移植時的最後更新日期: 2016-04-11T16:17:29.998+08:00
所有的練習我有開一個Github Project
模式名稱
模式描述、說明模式程式碼
簡單工廠模式
實作注意:建立一個static function(工廠function)決定(或選擇)建造物件是什麼。利用工廠模式決定產出的物件是什麼(這些物件將會執行相同的行為)
把creatSomthing放在factory類別中,並且設定成static,使用方式像下面這樣
something = factory::creatSomething(someThingType); //靜態工廠
工廠做出來的物件,會有相同的一組函式介面,意思是new出來的物件會執行相同的function然後產出物件,並且後續以相同的介面使用該物件。策略模式
實作注意:不同的function(演算法)使用同一組interface,繼承其interface的class目的在於呼叫其內含的function。利用策略決定(選擇)使用的function(或演算法)是什麼。
- 將interface放在class中,再繼承interface實作各種演算法。
- 將各種演算法放在同一個class,重新定義class的operator()。
omeTea BlackTea(TT_BLACKTEA);
BlackTea.shakeStrategy(); //介面=概念執行,不代表演算法實作
將演算法打包,我利用operator()()來實作。將演算法包進一個類別裡。(偽造的function)裝飾模式
call back function實現在物件導向中的做法。裝飾類別是被call back的function,本體類別是原本的觸發點,使用時才決定call back哪些function,使用相同的interface依序呼叫function。
本體與裝飾虛類別繼承自相同的interface。
Ice->SetDecorator(blackTea); //設定觸發本體
Milk->SetDecorator(Ice); //設定觸發本體時,同時又要觸發什麼(裝飾)…
//…
Milk.CreatDrank();
裝飾的設定可以用重載運算子串起來(+或-)。blackTea + Ice + Milk /* +… / //設定觸發的本體+觸發裝飾+觸發裝飾;
Milk.CreatDrank();
裝飾品裝在本體上,也可以裝在裝飾品上,最後用一個相同的function來串起來(call back)。通常用在程式執行時才可以決定到底這次要使用哪些function,所以先全部做出來,到時再用裝飾模式
代理模式
實作注意:設計一個class,擁有原本無法修改設計的class,並且與它繼承自同一個基礎類別。不修改原本的class之下,透明的擴充,擴充特性本身就是proxy的特色
class proxy
{
Excelfile xlsf; //使用代理模式擴充excel的類別
};
代理與被代理是衍生自同一個父類別。看似沒有什麼特色的代理模式,可以用來增加介面反應速度(buffer)。
使用一組function取代(擴充)真正接觸實體物件時付出的代價。
- 遠端代理(Remote):代理遠端程時執行,例如我們可以透過WebService的WSDL定義產生中介檔的函式庫,透過這個函式庫就可以存取WebService。
- 虛擬代理(Virtual):將需要秏費大量時間或是複雜的實體,利用代理模式的物件代替。
- 安全代理(Protect or Access):控制物件存取時的許可權。
- 智慧參考(Smart Reference):提供比原有物件更多的服務。
工廠方法模式
建構過程做在工廠裡的function,有時建構參數很多,有時建構時要透過另一個臨時的物件當作參數,要先建構它,再建構主要的物件。建立自訂建構過程的construction function群當工廠
將變動留給使用者
簡單工廠簡化了使用者的程式碼,卻需要不斷的變動工廠的程式碼才可以新增項目
工廠方法簡化了新增項目的部份,雖然看似複雜了使用者的程式碼。
//用這個決定物件是誰(不過,若要使用switch-case就…和簡單工廠一樣了XD
IFactory* factory = new ModFactory(); //在此決定要建的工廠function是什麼(工廠選擇,決定產線內容不同)
Operation* oper = factory->creatOperation(); //在這call construct function
工廠從簡單工廠→工廠方法之外,書上還有提到一種「反射」,之後怎麼做就繼續把書看下去吧!原型模式
複製指標指向的物件。利用函數複製「指標指向的物件」(包含物件內的成員屬性本身)
淺複製: 遇到成員指標,只複製其位址。
深複製: 遇到成員指標,複製整個物件(在該物件中,設計Clone並繼承prototype class)
className(const className& myself) //className自己的建構子
{
//other member var
ptr = myself.ptr->Clone()// 深層複製
}
className* Clone() //className是自己類別的類別名稱
{
return new className(this); // new一份自己(物件)回傳出去
}
樣版模式
實作注意:將共同的部份放到父類別,特別的部份放到子類別。透過父類別中public的function call back子類別中private的function。class classBasis
{
virtual void Detail() = 0; //子類別要實作的部份
public:
void template()
{
/do some thing/
Detail();
}
};
class classDerivative : public classBasis
{
void Detail(){} //設為private
};
FunctionDeri()不可以直接creat子類別的物件,再直接呼叫,一定是被call back的function。外觀模式
簡化API,隱藏複雜度,將各種類別放到一個類別裡面,透過簡化的fucntion呼叫複雜或多個function,達到簡化的作用;換句話說,外觀模式是建立一個class擁有許多class。當多個function符合概念整體性,就建造一個外觀。建造者模式
將建造條件與建造細節分開。- 建造條件
為預防漏掉任何建造條件,利用純虛擬函數強迫檢查是否全部必要的建造條件都有(在衍生類別)覆寫。(有點像工廠方法) - 建造細節
- 繼承builder這個純虛擬類別的衍生類別。
- 建造過程
擁有將建造條件的純虛擬,簡化介面呼叫(用一個function呼叫很多function)
//建造條件
class builder
{
/constructor or other function/
public:
virtual void functionA() = 0;
virtual void functionB() = 0;
virtual void functionC() = 0;
};
//建造細節
class builderForTarget
{
public:
void functionA(){}; //定義建造細節
void functionB(){};
void functionC(){};
};
//建造過程
class directory
{
builder m_builder; //子類別要實作的部份
public:
void function()
{
m_builder->functionA();
m_builder->functionB();
m_builder->functionC();
}
};
觀察者模式
做為雙向耦藕合的兩個類別,解耦之用,程式碼如下。class B的Update()一定要用一個B.cpp裝起來,如果放在B.h的話,call A::Call()會找不到定義。
這兩個類別彼此互耦,彼此的關係就是B等A呼叫而跟著更新訊息,所以稱B為觀察者。
//a.h
#include <vector>
#include "bbb.h"
class A
{
std::vector<B*> vb;
public:
void Call()
{
for (std::vector<B*>::iterator it = vb.begin(); it != vb.end(); ++it)
(it)->Update();
}
};
//b.h
#include <iostream>
class A;
class B
{
A a;
public:
void Update();
};
//b.cpp
#include “aaa.h”
#include "bbb.h"
void B::Update(){ a->Call(); }
程式碼可以解耦成這樣,讓介面與衍生類別耦合。衍生類別透過virtual,可以在定義中操作基礎類別當作是衍生類別。//a0.h
#include "b0.h"
struct A0
{
virtual void Add(B0* b) = 0;
virtual void Call() = 0;
};
//aaa.h
#include <vector>
#include "a0.h"
class A : public A0
{
std::vector<B0*> vb;
public:
void Add(B0* b)
{ vb.push_back(b); }
void Call()
{
for (std::vector<B0*>::iterator it = vb.begin(); it != vb.end(); ++it)
(it)->Update();
}
};
//b0.h
struct B0
{
virtual void Update() = 0;
};
//bbb.h
class B : public B0
{
A a;
public:
void Update()
{ a->Call(); };
};
這樣的實作方式,常用在Client/Server
Document/View
這種一個地方修改,其它看見該文件的view都要跟著更新的程式碼。
也可以說是重覆利用「call一個function,這個function會call其它function的一種機制」。
抽象工廠模式
簡單工廠模式: 用變數建立物件。工廠方法模式: 用介面建立物件(讓子類別決定建立的物件。)
抽象工廠模式: 用介面建立介面(讓子類別決定建立的介面,讓介面操作物件。)
//用這個決定物件是誰(不過,若要使用switch-case就…和簡單工廠一樣了XD
//iFactory* factory = new SqlSevFactory();
iFactory* factory = new AccessFactory();
iUser* iu = factory->createUser();
User* user = new User();
iu->Insert(user);
iu->getUser(1);
iDepartment* id = factory->creatDepartment();
Department* dept = new Department();
id->Insert(dept);
id->getDeptName(1);
狀態模式
實作注意:將if-else換成一個State類別動態連結的function call,該function定義了各種不同的State的決策(邏輯)內容。function裡描述「狀態的轉換」總是用長長的if-else。和FSM相同的特色在於「目前狀態會決定前往特定的下一個狀態」,不同的地方在於「輸出和狀態有關,還是和輸入有關,在此不重要」。要設計成邏輯與運算分離,邏輯的function就是狀態模式,容易變動的部份就是增減狀態的部份
#ifndef STATE_H
#define STATE_H
class Something; //原本有很長的if-else的class
class State
{
public:
virtual void UpdateState(Something& w) = 0;
};
#endif
轉接器模式
和proxy代理模式非常的像- 轉接器模式「轉接與被轉接,不需要衍生自同一個基礎類別」
- 代理模式「代理與被代理,都需要洐生自同一個基礎類別」
備忘錄模式
組合模式
迭代器模式
獨體模式
橋接模式
將兩種可形成組識的獨立概念拆開設計。並且可以自由組合成所有排列組合的結果。
就像是模組化設計、再組合起來的感覺。
命令模式
用基礎類別指標指向衍生類別物件,將裝著基礎類別指標容器的增加、減少,透過基礎類別的function界面,呼叫真實執行的函數。最後利用動態連結的特性,用一個迴圈一次執行。
在增加減少的過程,可以將衍生類別加入容器中。
將容器與這一系列的動作包成Command類別,也可以隱藏指標在容器中的複雜度。
責任鍊模式
發表於
tags:
{ Design Pattern }