打字猴:1.700483629e+09
1700483629 System.out.println(u);
1700483630
1700483631 }
1700483632
1700483633 }
1700483634
1700483635 }
1700483636
1700483637 运行结果如下所示:
1700483638
1700483639 ===年龄大于20岁的用户===
1700483640
1700483641 用户名:马七年龄:25
1700483642
1700483643 用户名:杨八年龄:30
1700483644
1700483645 用户名:侯九年龄:35
1700483646
1700483647 用户名:布十年龄:40
1700483648
1700483649 结果非常正确,但是这样的一个框架基本上是不能适应业务变化的,为什么呢?业务变化虽然无规则,但是可以预测,比如我们这个查询,今天要查找年龄大于20岁的用户,明天要查找年龄小于30岁的用户,后天要查找姓名中包含“国庆”两个字的用户,想想看IUserProvider接口是不是要一直修改下去?接口是契约,而且我们一直提倡面向接口编程,但是在这里接口竟然都可以修改,是不是发现设计有很大问题了!
1700483650
1700483651 问题发现了,就要想办法解决。再回顾一下编写的代码,注意看findUserByAgeThan和findUserByNameEqual两个方法,两者的代码有什么不同呢?除了if后面的判断条件不同外,就没有不同的地方了,我们一直在说封装变化,这两段程序就仅仅有这一个变化点,我们是不是可以把它封装起来呢?完全可以,把它们两者的共同点抽取出来,先修改一下接口,如代码清单37-5所示。
1700483652
1700483653 代码清单37-5 修正后的接口
1700483654
1700483655 public interface IUserProvider{
1700483656
1700483657 //根据条件查找用户
1700483658
1700483659 public ArrayList<User>findUser(boolean condition);
1700483660
1700483661 }
1700483662
1700483663 这个接口的设计想法非常好,但是参数condition很难实现,看看findUserByAgeThan、findUserByNameEqual这两个方法,怎么才能把两者的不同点设置成一个布尔型呢?如果需要在IUserProvider对象外判断后传递进来,那我们的封装就没有任何意义了——目前为止,这个方案有问题了。
1700483664
1700483665 继续考虑,既然不能在封装外运算,那就把整个条件都进行封装,由IUserProvider自己实现运算。好方法!那我们就设计一个这样的类,我们叫它规格类,什么意思呢?它是对一批对象的说明性描述,它依照基准判断候选对象是否满足条件。思考后,我们设计出类图,如图37-2所示。
1700483666
1700483667
1700483668
1700483669
1700483670 图37-2 加入规格后的设计类图
1700483671
1700483672 在该类图中建立了一个规格书接口,它的作用就是定制各种各样的规格,比如名字相等的规格UserByNameEqual、年龄大于基准年龄的规格UserByAgeThan等等,然后在用户操作类中采用该规格进行判断。User类没有任何改变,如代码清单37-1所示,不再赘述。
1700483673
1700483674 规格书接口是对全体规格书的声明定义,如代码清单37-6所示。
1700483675
1700483676 代码清单37-6 规格书接口
1700483677
1700483678 public interface IUserSpecification{
[ 上一页 ]  [ :1.700483629e+09 ]  [ 下一页 ]