形式一."见兔撒鹰". 例:
1 public class
Company{ 2 private List members=null ; 3 4 public void addMember(Member member){ 5 if(members=null ){ 6 members=new ArrayList(); 7 } 8 9 members.add(member); 10 } 11 } 12 | |
异曲同工的另外一个例子:
1 public class
Singleton{ 2 private static Singleton instance=null ; 3 4 public static synchronized Singleton getInstance(){ 5 // 要用的时候再把Singleton建立起来 6 if(instance==null ){ 7 instance=new Singleton(); 8 } 9 10 return instance; 11 } 12 } 13 形式二."只管结果,不顾过程" 题设:有个数不定元素的列表(allTodoes),需要从中取N个,起始位置不限,你怎么编写程序. 很多人开始进行越界的判断,出来一堆if else,有时还需要在纸上写好思路,完毕后还有多方测试,生怕出错,即使编写好后其他人维护起来也是小心翼翼的.其实没必要这么麻烦. 例.
1 int start=pageIndex*
pageSize; 2 int end=start+ pageSize; 3 4 for(int i=start;i<end;i++ ){ 5 try { 6 todoResult.addTodo((Todo)allTodoes.get(i)); 7 } 8 catch (Exception ex){ 9 continue ; 10 } 11 } 题外话:分支和循环语句天生就不容易理解,尤其是在嵌套较深的时候,因为这是机器的思维特性.还是try...catch...比较贴近人类思维.
需求:从公司的职员列表中,找出男性且年龄大于22的成员. 传统写法:
1 List allmembers=company.getMembers();// 取得所有成员
2 List results=new ArrayList();// 结果列表 3 4 for(Iterator it= allmembers.iterator();it.hasNext();){ 5 Member member= (Member)it.next(); 6 7 if(member.getAge()>22 && member.isMale()){ // 筛选,这里是把查询条件和遴选过程融合在一起,条件一变立即就得加个分支. 8 results.add(member); 9 } 10 } 11
这种写法没有错,但是不是面向对象的写法,它有以下缺陷: 真正符合OO的查询应该是这样:
1 MemberFilter filter1=new
MemberFilter(){ 2 public boolean accept(Member member) { 3 return member.isMale() && member.getAge()>22 ; 4 } 5 }; 6 7 List ls=company.listMembers(filter1);
这段代码成功的把查询条件作为一个接口分离了出去,接口代码如下:
1 public interface
MemberFilter{ 2 public boolean accept(Member member); 3 } 而类Company增加了这样一个函数:
1 public
List listMembers(MemberFilter memberFilter){ 2 List retval=new ArrayList(); 3 4 for(Iterator it= members.iterator();it.hasNext();){ 5 Member member= (Member)it.next(); 6 7 if (memberFilter.accept(member)){ 8 retval.add(member); 9 } 10 } 11 12 return retval; 13 } 这就把模板代码归结到了类内部,外面不会重复书写了.Company也同时拥有了数据和行为,而不是原来的数据容器了. 形式四."化繁为简" 原始代码(VB代码,但应该不妨碍理解):
1 Dim
count1 2 count1 = salary.Value + USA.Value * Drate + JAN.Value * Jrate - 4000 3 If count1 < 500 Then 4 tax.Value = count1 * 0.05 5 ElseIf count1 < 2000 Then 6 tax.Value = count1 * 0.1 - 25 7 ElseIf count1 < 5000 Then 8 tax.Value = count1 * 0.15 - 125 9 ElseIf count1 < 20000 Then 10 tax.Value = count1 * 0.2 - 375 11 ElseIf count1 < 40000 Then 12 tax.Value = count1 * 0.25 - 1375 13 ElseIf count1 < 60000 Then 14 tax.Value = count1 * 0.3 - 3375 15 Else 16 tax.Value = count1 * 0.3 - 3375 17 End If 变换如下:
1 public class
TaxItem{ 2 float limit; // 月薪界限 3 float ratio;// 税率 4 float discount;// 折扣 5 6 public TaxItem(float limit,float ratio,float discount){ 7 this.limit= limit; 8 this.ratio= ratio; 9 this.discount= discount; 10 } 11 12 public TaxItem(){ 13 this(0.0f,0.0f,0.0f ); 14 } 15 16 public float getDiscount() { 17 return discount; 18 } 19 20 public float getLimit() { 21 return limit; 22 } 23 24 public float getRatio() { 25 return ratio; 26 } 27 } 28 29
1 public class
TaxCaculator{ 2 private static ArrayList list=new ArrayList(); 3 4 public TaxCaculator(){ 5 // 这里把各个等级加入到链表中,注意添加顺序是由小到大 6 list.add(new TaxItem(500.0f,0.05f,0.0f )); 7 list.add(new TaxItem(2000.0f,0.1f,25.0f )); 8 list.add(new TaxItem(5000.0f,0.15f,125.0f )); 9 list.add(new TaxItem(20000.0f,0.2f,375.0f )); 10 list.add(new TaxItem(40000.0f,0.25f,1375.0f )); 11 list.add(new TaxItem(60000.0f,0.3f,3375.0f )); 12 } 13 14 // 这个函数用来计算所得税 15 public float getTax(float salary){ 16 TaxItem item=new TaxItem(); 17 18 for(int i=0;i<list.size();i++ ){ 19 item= (TaxItem)list.get(i); 20 21 if(salary> item.getLimit()){ 22 continue ; 23 } 24 else { 25 break ; 26 } 27 } 28 29 // 返回最终结果,当然,这个公式也可以放在TaxItem 类中,这里就见仁见智了。 30 return salary*item.getRatio()- item.getDiscount(); 31 } 32 }
1 TaxCaculator taxCaculator=new
TaxCaculator(); 2 3 float salary=1000 .f; 4 System.out.println("Salary="+salary +" Tax="+ taxCaculator.getTax(salary)); 5 6 salary=2000 .f; 7 System.out.println("Salary="+salary +" Tax="+ taxCaculator.getTax(salary)); 8 9 salary=3000 .f; 10 System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary));
举例如下: if(命令==”AAA”){ 这种方法在命令较少时是有效的,当命令众多时,if语句和相关的函数将会形成一个巨集,给检查,维护和扩充带来了很大的不便,久而久之将会成为系统性能提升的瓶颈。 一个成功的软件程序必须尽可能简单并易于重构和扩展,在命令模式和Java反射机制的帮助下,我们可以从容解决上述问题,达到简单并易于重构和扩展的要求。以下将简要说明解决方案。 1. 制作一个命令的抽象接口.
1 public interface
Command{ 2 public abstract void execute(String[] args); 3 }
2. 让每种命令都实现这个接口.
1 // 命令一
2 public class CommandType01 implements Command{ 3 public void execute(String[] args){ 4 System.out.println("/n commandType01 start!" ); 5 System.out.print("/t commandType01 Length="+ args.length); 6 System.out.println("/n commandType01 End!" ); 7 } 8 } 9 10 // 命令二 11 public class CommandType02 implements Command{ 12 public void execute(String[] args){ 13 System.out.println("/n commandType02 start!" ); 14 15 System.out.print("/t commandType02 is:" ); 16 for (String item:args){ 17 System.out.print("/t "+ item); 18 } 19 20 System.out.println("/n commandType02 End!" ); 21 } 22 } 23 24 // 命令三 25 public class CommandType03 implements Command{ 26 public void execute(String[] args){ 27 System.out.println("/n commandType03 start!" ); 28 System.out.print("/t commandType03 last Nation="+args[args.length-1 ]); 29 System.out.println("/n commandType03 End!" ); 30 } 31 } 32 33
3. 将命令防置到命令中心中去
1 public class
Mediation{ 2 Command cmmd;// 命令对象的引用 3 String[] cmmdArgs;// 参数列表 4 5 public Mediation(){ 6 7 } 8 9 public void fetchCommand(String strCmmd){ 10 cmmdArgs=strCmmd.split("/s+");// 分析原始命令 11 12 String className="Command"+cmmdArgs[0];// 根据分析后命令的第一个参数得到类名 13 14 try { 15 Class cls=Class.forName(className);// 利用反射机制得到类 16 cmmd=(Command)cls.newInstance();// 由类得到类实例 17 } 18 catch (Exception ex){ 19 ex.printStackTrace(); 20 } 21 } 22 23 24 public void executeCommand(){ 25 cmmd.execute(cmmdArgs);// 执行命令对象的execute方法 26 } 27 28 }
1 Mediation mediation = new
Mediation(); 2 // 取得命令一并执行 3 mediation.fetchCommand("Type01 AB CD" ); 4 mediation.executeCommand(); 5 6 // 取得命令二并执行 7 mediation.fetchCommand("Type02 1 2 3 4" ); 8 mediation.executeCommand(); 9 10 // 取得命令三并执行 11 mediation.fetchCommand("Type03 USA Russia China" ); 12 mediation.executeCommand(); 13 执行效果如下: commandType02 start! commandType03 start! 由上可见,我们使用反射机制消除了庞大的分支语句,把命令的执行过程分散到了Command的各个子类中,降低了命令类和控制中心类的耦合程度,达到了简单并易于重构和扩展的要求。如果新增一种命令,只需增加Command的一个子类就可以了。 注意:这里对命令和Command的子类类名有特殊要求,即一种命令对应一种子类,子类类名可以由命令的首个参数简单组合而来,否则还是避免不了分支语句。 以上五种组织形式,若加以灵活运用,相信能减少一些代码臭味. |
为你的程序锦上添花的五种程序组织形式
最新推荐文章于 2022-07-02 09:18:43 发布