看侯捷老师的课程讲,面对对象的类的组织关系有三种,组合,委托,和继承。
组合:一个类“有一个”另一个类型的实例作为成员,如
class A {
B b;
}
委托:一个类有另一个类的实例的指针类型作为成员,如
class A {
B *b
}
继承:一个类,是另一个类的一种派生, 如
class A:public B{}
作为一个java程序员,组合和继承是常常用的,只是对委托这种东西不是很理解。
这篇文章结合java对委托做一个解析
委托模式下类成员就是java里说的接口
在java web中的业务一般都会分为:表现层,业务逻辑层,数据访问层。
其中业务逻辑层处理业务逻辑,有必要时调用数据访问层操作数据库的数据。
比如一个商城系统要获取一条订单信息有关的业务逻辑层的类可能是下面这样
// 业务逻辑层处理订单信息的类
class OrderServiceImp {
// 数据访问层委托对象
OrderDao orderDao;
Order getById(int id) { return orderDao.getById(id); }
}
这个orderDao在java里是个接口,在c++里实际就是存放的基类指针。这就引出下面的话题。
委托的目的:解耦
上面说的orderDao它的代码都是抽象的,用c++表示就是它的成员函数都是virtual xxx = 0;
这样做有什么好处呢,小标题里也说了,解耦。
OrderDao只对外提供增删改查方法的接口,不必展示内部的细节,OrderService将一些操作“委托”给OrderDao,也不必纠结于OrderDao的实现细节。
使用时,只需让orderDao“指针”指向自己写的派生类,假如今天我用mysql作为数据库存储数据,明天用oracle,只需使用时让OrderService的成员指针指向继承了OrderDao的派生类,同样的代码就展现出了不同的效果(c++有个规定,派生类向基类的自动类型转换只对指针或引用类型有效。)
没代码说个XX
今天状态不太好,总感觉表达不出来我真正想说的,还是上一段代码吧,模拟一段情景。
假如我要做一个游戏,一开始没有美工,只好用ascii字符表示人物,场景,物品。有个控制ui的类
class UI {
virtual void draw();
}
我的地图类成员包含一个UI类的指针,当生成地图时调用draw函数绘制地图
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界面地图就生成了。
现在投资商来投了一个亿,我请了个美工,画出超牛的3d地图。那我现在要将画出地图,人物,菜单,物品等等界面都改为画3d的,我要改写所有类的代码吗?还好不用,我只需要修改UI的派生类Ascii,或者重新写一个派生类,这样的话,甚至游戏程序的其他部分都不知道界面有改变,业务逻辑等等都可以直接使用。
class 3dUI:public UI {
void draw() override { ... }
}
这样将自己的任务可以分离出来的地方,委派给别人的思想,实际上就是面对对象设计的核心要素高内聚,低耦合的体现
在设计类时只要把握住这个核心要素,其他都是实现它的小技巧而已。
网友评论