结束了内部标示的示例后,我们开始讨论另一种做法:隐藏委托(Hidden Delegate)
public class PersonImpHD implements Person, Salesman, Engineer,Manager{
// implement manager
public void makeManager () {
_manager = new ManagerImpHD();
};
public boolean isManager (){
return (_manager != null);
};
private void requireIsManager () {
if (! isManager()) throw new PreconditionViolation ("Not a Manager") ;
};
public void budget (Money value) {
requireIsManager();
_manager.budget(value);
};
public Money budget () {
requireIsManager ();
return _manager.budget();
};
private ManagerImpHD _manager;
}
class ManagerImpHD {
public ManagerImpHD () {
};
public void budget (Money value){
_budget = value;
};
public Money budget (){
return _budget;
};
private Money _budget;
}
|
使用这种隐藏委托的方法,我们把和经理相关的行为和数据移到了经理对象中,从而大大简化了员工类。这种方法非常适用于角色的子类包含了很多的额外行为和特性的情况。但是这种方法还是没能够克服原来问题的一个缺陷-员工类仍然持有角色子对象的所有接口,而且员工类必须处理对不同方法的选择,即决定调用何种方法,传递何种参数。这样我们又理所当然的想到了继承机制,它能够很好的处理多态,为什么我们不能够利用面向对象语言提供给我们的便利之处呢?
于是乎,我们想到了利用四人帮在设计模式一书中谈到的状态对象模式的设计思路。如果我们的子对象比较稳定,相互之间也不存在并集,那么采用这种模式预先划分好子对象是非常好的一种思路。当然,我们这里已经吸髓知味,知道说隐藏对象的技巧有助于向客户端隐藏具体的实现。因此,我们继续沿用这种思路,这样,我们的思路就基本上可以这样描述:
为每一个角色定义一个对象,这些对象对客户端不可见,因此称为隐藏对象。
为这些隐藏对象定义一个父类,一方面可以利用继承的多态机制实现方法的选
择和类型安全,另一方面可以把角色的通用行为移至父类中,以实现代码的重用。
设计一个会话类,实现所有的角色接口,但其自身不需要处理实现,而是把具体的实现委托给前面设计好的继承树。
从下面的代码中,我们可以清晰的看到我们提出的这几点步骤是如何贯彻到代码中的:
public class PersonImpHD implements Person, Salesman, Engineer,Manager{
public static Salesman newSalesman (String name){
PersonImpHD result;
result = new PersonImpHD (name);
result.makeSalesman();
return result;
};
public void makeSalesman () {
_job = new SalesmanJobHD();
};
public boolean isSalesman () {
return _job.isSalesman();
};
public void numberOfSales (int value){
_job.numberOfSales(value);
};
public int numberOfSales () {
return _job.numberOfSales();
};
private JobHD _job;
};
abstract public class JobHD {
private void incorrectTypeError() {
throw new PreconditionViolation("Incorrect Job Type");
};
public boolean isSalesman () {
return false;
};
public void numberOfSales (int value) {
incorrectTypeError();
};
public int numberOfSales (){
incorrectTypeError();
return 0;//value not returned since exception is thrown,
compiler needs return
};
}
public class SalesmanJobHD extends JobHD{
public boolean isSalesman () {
return true;
};
public void numberOfSales (int value){
_numberOfSales = value;
};
public int numberOfSales () {
return _numberOfSales;
};
private int _numberOfSales = 0;
}
|
在员工类中几乎不存在任何的实现代码,所有的请求都委托给了隐藏对象们。从这里的例子还不能够明显的看出多态的优势,我们再看一个例子:
public class PersonImpHD implements Person, Salesman, Engineer,Manager{
public Money payAmount (){
return _job.payAmount(this).add(managerBonus());
};
…
abstract public class JobHD {
abstract public Money payAmount (Person thePerson);
…
public class SalesmanJobHD extends JobHD{
public Money payAmount (Person thePerson) {
return thePerson.salary().add (Money.dollars(5).multiply(_numberOfSales));
};
|
这一段计算薪水的代码就完全体现了多态的优势了。这里还有一些小技巧,可以看到,payAmount方法需要用到person类的数据,因此,person类在调用payAmount方法时将自己作为参数传递给了JobHD类。这种方式称为自委托(Self Delegation)[Beck]。
可以看到,对新增加角色的支持也同样简单,只需要从JobHD再继承一个子类下来就行了。由于接口是由person类来实现的,因此所有的改动都是在背后完成的,这可能就是隐藏对象的优势所在了。对于客户端来说,对于任何一个接口,都只需要对person进行实例化,然后根据不同的接口定义的不同的标准来调用就可以了,至于所有的实现细节,客户端根本就不知道。当然必须增加接口,但现在无论是哪一种平台都支持这种机制。因此,我们可以对从内部标志模式到隐藏委托模式,再到状态对象模式做一个简单的总结:
如果您对本文有任何疑问或者建议,请到讨论区发表您的意见:
>>
论坛入口 <<
上一篇:
对象建模笔记--角色建模1
下一篇:
对象建模笔记--角色建模3
【文章评论】
【收藏本文】
【推荐好友】
【打印本文】
【我要投稿】 【论坛讨论】