ParticipantsInDB不再继承DBTable。代替的,它里面有一个属性引用了一个DBTable对象,然后调用这个DBTable的clear, getConn, getTableName 等等方法。

  代理(delegation)

  其实我们这边可以看一下ParticipantsInDB的clear方法,这个方法除了直接调用DBTable的clear方法以外,什么也没做。或者说,ParticipantsInDB只是做为一个中间介让外界调用DBTable的方法,我们管这样传递调用的中间介叫“代理(delegation)”。

  现在,之前有bug的那部分代码编译不过了:

ParticipantsInDB partsInDB = ...;
Participant kent = new Participant(...);
Participant paul = new Participant(...);
partsInDB.clear();
partsInDB.addParticipant(kent);
partsInDB.addParticipant(paul);
partsInDB.deleteParticipant(kent.getId());
//编译出错:因为在ParticipantsInDB里面已经没有getCount这个方法了!
System.out.println("There are "+partsInDB.getCount()+ "participants");


  总结一下:首先,我们发现,ParticipantsInDB 和 DBTableIn之间没有继承关系。然后我们将“代理”来取代它们的继承。“代理”的优点是,我们可以控制DBTable的哪些方法可以“公布(是设为public)”(比如clear方法)。如果我们用了继承的话,我们没得选择,DBTable里面的所有public方法都要对外公布!

  抽取出父类中没必要的功能

  现在,我们来看一下另一个例子。假定一个Component代表一个GUI对象,比如按钮或者文本框之类的。请认真阅读下面的代码:

abstract class Component {
boolean isVisible;
int posXInContainer;
int posYInContainer;
int width;
int height;
...
abstract void paint(Graphics graphics);
void setWidth(int newWidth) {
...
}
void setHeight(int newHeight) {
...
}
}
class Button extends Component {
ActionListener listeners[];
...
void paint(Graphics graphics) {
...
}
}
class Container {
Component components[];
void add(Component component) {
...
}
}


  假定你现在要写一个时钟clock组件。它是一个有时分针在转动的圆形的钟,每次更新时针跟分针的位置来显示当前的时间。因为这也是一个GUI组件,所以我们同样让它继承自Component类:

class ClockComponent extends Component {
...
void paint(Graphics graphics) {
//根据时间绘制当前的钟表图形
}
}

$news-page$

  现在我们有一个问题了:这个组件应该是个圆形的,但是它现在却继承了Component的width跟height属性,也继承了setWidth 和 setHeight这些方法。而这些东西对一个圆形的东西是没有意义的。

  当我们让一个类继承另一个类时,我们需要再三的想想:它们之间是否有继承关系?ClockComponent是一个Component吗?它跟其他的Compoent(比如Button)是一样的吗?

  跟ParticipantsInDB的那个案例相反的是,我们不得不承认ClockComponent确实也是一个Component,否则它不能像其他的组件那样放在一个Container中。因此,我们只能让它继承Component类(而不是用“代理”)。

  它既要继承Component,又不要width, height, setWidth 和 setHeight这些,我们只好将这四样东西从Component里面拿走。而事实上,它也应该拿走。因为已经证明了,并不是所有的组件都需要这四样东西(至少ClockComponent不需要)。

  如果一个父类描述的东西不是所有的子类共有的,那这个父类的设计肯定不是一个好的设计。

  我们有充分的理由将这些移走。

  只是,如果我们从Component移走了这四样东西,那原来的那些类,比如Button没了这四样东西,而它确实又需要这些的(我们假定按钮是方形的)。

  一个可行的方案是,创建一个RectangularComponent类,里面有width,height,setWidth和setHeight这四样。然后让Button继承自这个类:

abstract class Component {
boolean isVisible;
int posXInContainer;
int posYInContainer;
...
abstract void paint(Graphics graphics);
}
abstract class RectangularComponent extends Component {
int width;
int height;
void setWidth(int newWidth) {
...
}
void setHeight(int newHeight) {
...
}
}
class Button extends RectangularComponent {
ActionListener listeners[];
...
void paint(Graphics graphics) {
...                     }
}
class ClockComponent extends Component {
...
void paint(Graphics graphics) {
//根据时间绘制当前的钟表图形
}
}