值之间的依赖
在一些情况下,只有当值对象的其他属性被分配了值,一个属性才有可能是可选的。属性的“可选性” sometimesOptional依赖于actionType属性的值。可能action属性持有的值代表了actions:例如addSomething = 1, updateSomething = 2, 和 deleteSomthing = 3。如果action的值是1或者3,sometimesOptional属性不是可选的;如果action的值是2,则是可选的。当我们为actionType赋值的时候,我们必须设置sometimesOptional的可选性:
public void setActionType(int actionType)
{
this.actionType = actionType;
super.clearOptionalMethods( );
switch( this.actionType )
{
case ActionParameter.ACTION_ADD :
super.addOptionalMethod( "getSometimesOptional4" );
super.addOptionalMethod( "getSometimesOptional5" );
break;
case ActionParameter.ACTION_UPDATE :
super.addOptionalMethod( "getSometimesOptional1" );
break;
case ActionParameter.ACTION_REMOVE :
super.addOptionalMethod( "getSometimesOptional1" );
super.addOptionalMethod( "getSometimesOptional2" );
super.addOptionalMethod( "getSometimesOptional3" );
break;
default :
break;
}
}
你会看到清除可选方法列表是必需的,因为如果你给actionType赋值超过一次的话,越来越多的方法将作为可选的方法添加进来。另外的一个解决方法包括实现一个AddActionParameter,一个UpdateActionParameter和一个RemoveActionParameter,它们都是从AbstractParameter类继承得来。那么你可能不需要actionType属性。但是拥有actionType属性的类存在并且经常被使用,对该类使用反射非常容易,你必须使用Switch语句。
展望
现在,我们可以考虑继承AbstractParameter的更多的功能——例如,范围校验。AbstractParamter需要一个数据结构来存储范围值。HashMap能够做到,它以方法名作为key存储范围对象。或者你可以检测是否一个String类型的值包含一些定义的字。等等。你也可以考虑Perl 5的正则表达式。所有的这些检测都可以在Validator类里实现,它实现了IClassAttributeValidator接口。如果你想使用属性的null检测和附加值检测,那么你可以写一个子类来继承GenericClassAttributeValidator。
在J2EE应用里,值对象经常被用来在客户端和服务器之间传递业务过程的数据。但是,如果你仅仅在服务器端校验这些值对象的属性,你常常不得不因为一个错误的非可选属性为null而取消业务过程。你必须中断业务过程,而向客户端发送一个错误页面。这是一个好的实践:在服务端应用这些validators的同时,你也可以以委派的形式在客户端应用它们。在客户端检测值对象可以避免不必要的对服务器的请求和降低网络堵塞。
写一次,使用多次
如果你使用我描述的方法来检测你的值对象的属性,你可以永远只增加值对象的属性——不用改变validator,它们能够被自动检测是否为null。你也可以不用改变validator而改变一个属性的条件。而且,当然,一个已有的validator也能够校验一个未来的值对象,如果这个值对象继承AbstractParameter的话。还有,你也可以不用改变值对象而写一个额外的validators,因为validators实现的是Visitor模式。这就是所谓的写一次,使用多次。