看侯捷老師的課程講,面對對象的類的組織關系有三種,組合,委托,和繼承。
組合:一個類“有一個”另一個類型的實例作為成員,如
class A {
B b;
}
委托:一個類有另一個類的實例的指針類型作為成員,如
class A {
B *b
}
繼承:一個類,是另一個類的一種派生, 如
class A:public B{}
作為一個java程序員,組合和繼承是常常用的,只是對委托這種東西不是很理解。
這篇文章結合java對委托做一個解析
委托模式下類成員就是java里說的接口
在java web中的業(yè)務一般都會分為:表現(xiàn)層,業(yè)務邏輯層,數(shù)據(jù)訪問層。
其中業(yè)務邏輯層處理業(yè)務邏輯,有必要時調(diào)用數(shù)據(jù)訪問層操作數(shù)據(jù)庫的數(shù)據(jù)。
比如一個商城系統(tǒng)要獲取一條訂單信息有關的業(yè)務邏輯層的類可能是下面這樣
// 業(yè)務邏輯層處理訂單信息的類
class OrderServiceImp {
// 數(shù)據(jù)訪問層委托對象
OrderDao orderDao;
Order getById(int id) { return orderDao.getById(id); }
}
這個orderDao在java里是個接口,在c++里實際就是存放的基類指針。這就引出下面的話題。
委托的目的:解耦
上面說的orderDao它的代碼都是抽象的,用c++表示就是它的成員函數(shù)都是virtual xxx = 0;
這樣做有什么好處呢,小標題里也說了,解耦。
OrderDao只對外提供增刪改查方法的接口,不必展示內(nèi)部的細節(jié),OrderService將一些操作“委托”給OrderDao,也不必糾結于OrderDao的實現(xiàn)細節(jié)。
使用時,只需讓orderDao“指針”指向自己寫的派生類,假如今天我用mysql作為數(shù)據(jù)庫存儲數(shù)據(jù),明天用oracle,只需使用時讓OrderService的成員指針指向繼承了OrderDao的派生類,同樣的代碼就展現(xiàn)出了不同的效果(c++有個規(guī)定,派生類向基類的自動類型轉換只對指針或引用類型有效。)
沒代碼說個XX
今天狀態(tài)不太好,總感覺表達不出來我真正想說的,還是上一段代碼吧,模擬一段情景。
假如我要做一個游戲,一開始沒有美工,只好用ascii字符表示人物,場景,物品。有個控制ui的類
class UI {
virtual void draw();
}
我的地圖類成員包含一個UI類的指針,當生成地圖時調(diào)用draw函數(shù)繪制地圖
class Map {
public:
void draw() { ui->draw(); }
void setup(UI *u) { ui = u; }
private:
UI *ui;
}
使用ascii字符的界面
class AsciiUI:public UI {
void draw() override {
// 打印界面
}
}
在游戲主程序里,我要生成地圖
int main() {
Map p;
AsciiUI a;
p.setup(a);
p.draw();
}
這樣,一個ascii界面地圖就生成了。
現(xiàn)在投資商來投了一個億,我請了個美工,畫出超牛的3d地圖。那我現(xiàn)在要將畫出地圖,人物,菜單,物品等等界面都改為畫3d的,我要改寫所有類的代碼嗎?還好不用,我只需要修改UI的派生類Ascii,或者重新寫一個派生類,這樣的話,甚至游戲程序的其他部分都不知道界面有改變,業(yè)務邏輯等等都可以直接使用。
class 3dUI:public UI {
void draw() override { ... }
}
這樣將自己的任務可以分離出來的地方,委派給別人的思想,實際上就是面對對象設計的核心要素高內(nèi)聚,低耦合的體現(xiàn)
在設計類時只要把握住這個核心要素,其他都是實現(xiàn)它的小技巧而已。