继往开来 吐故纳新
日历
网志分类
· 所有网志 (990)
· 个人作品 (62)
· 软件设计 (33)
· 面向对象编程 (22)
· JavaAPI (39)
· Java开源工具 (31)
· Swing (34)
· Java语法细节 (39)
· 样式表CSS (12)
· XML (10)
· J2EE(JavaEE) (23)
· 算法数据结构 (64)
· 正则表达式 (4)
· 软件知识 (6)
· Java线程 (9)
· Web开发.Jsp/Servlet/Struts (20)
· 程序随想录 (7)
· Spring (5)
· Hibernate (7)
· J2SE 高级 (2)
· J2SE 高级 (0)
· Web开发.Ajax (16)
· Web开发.JavaScript (43)
· DB4O (2)
· Web开发.CSS/Html (22)
· C# (20)
· ERP (4)
· JDBC (1)
· 编程资源 (16)
· 编程感悟 (29)
· DB/Sql (13)
· VB (29)
· VC (2)
· 桌面脚本 (3)
· 新兴软件 (3)
· 英语学习 (21)
· 网文转载 (159)
· 职场风云 (39)
· 诗词歌赋 (32)
· 生活感言 (77)
· 奇文共赏 (13)
· 财经纵横 (6)
· 未分类 (11)
站内搜索
友情链接
· 歪酷博客
· 我的歪酷 非非共享界
· 偶要雷锋
· 豆瓣
· nczonline
· 当当网
· easyjf中文站
· Donews
· 天极Java文章列表
· W3CSchool
· taiten的BLOG
· Dojo中国
· Dojo
· Extjs.com
· Lifehack中文网志
· JaveEye的一个AS专题
· Banq's JDon
· Java 中文网址大全
· 梦想Java
· 360Doc个人图书馆
· java开源大全
· 我在硅谷动力的软件下载站
· 站长中国
· 随意贴
· CSS教学素材站
· java 参考中文站
· 面向构件与SOA社区
· 彩字生成
· 派派小说论坛
· 如坐春风
· 英语学习网
· BBC CHina
· www.dlbang.com
· 古文竖排格式在线转化工具
· 免费家谱
· 图片上传基地
· 风景壁纸
· 和风细雨
· MyC#BlogInCsdn

订阅 RSS

0207422

歪酷博客

开此博一为经验积累,二为资料收集,三为同道交流,四为资源共享.
« 上一篇: 程序员的职业道路探究 下一篇: 快速开发九大要则 »
Junglesong @ 2007-06-05 13:17

一."用到再说"结构.
如果有一个类有一个集合成员,可以在为此成员添加元素时再把具体集合建立起来,以免浪费空间和时间.

例1:
public class Company{
    private List members=null;

    public void addMember(Member member){
     if(members=null){
    members=new ArrayList();
      }

     members.add(member);
    }
}


异曲同工的另外一个例子:
public class Singleton{
       private static Singleton instance=null;

       public static synchronized Singleton getInstance(){
   // 要用的时候再把Singleton建立起来
   if(instance==null){
     instance=new Singleton();
   }      

   return instance;
       }
}

二."试试再说"结构
从集合中取区间元素时,直接从上下限之间取来,让try...catch...去处理越界的事.

题设:有个数不定元素的列表(allTodoes),需要从中取N个,起始位置不限,你怎么编写程序.

很多人开始进行越界的判断,出来一堆if else,有时还需要在纸上写好思路,完毕后还有多方测试,生怕出错,即使编写好后其他人维护起来也是小心翼翼的.其实没必要这么麻烦.

例2.
  int start=pageIndex*pageSize;
  int end=start+pageSize;
 
  for(int i=start;i<end;i++){
   try{
    todoResult.addTodo((Todo)allTodoes.get(i));
   }
   catch(Exception ex){
    continue;
   }
  }

题外话:分支和循环语句天生就不容易理解,尤其是在嵌套较深的时候,因为这是机器的思维特性.还是try...catch...比较贴近人类思维.


三."凭文件领人"结构
在查询中,如果把查询条件和遴选过程分开来更有益,程序也因此解耦合.这才是OO化的查询.

需求:从公司的职员列表中,找出男性且年龄大于22的成员.

传统写法:
  // 传统查询
  List allmembers=company.getMembers();// 取得所有成员
  List results=new ArrayList();// 结果列表
 
  for(Iterator it=allmembers.iterator();it.hasNext();){
   Member member=(Member)it.next();
  
   if(member.getAge()>22 && member.isMale()){  // 筛选,这里是把查询条件和遴选过程融合在一起,条件一变立即就得加个分支.
    results.add(member);
   }
  }
  System.out.println(results); // 输出结果

这种写法没有错,但是不是面向对象的写法,它有以下缺陷:
1.查询条件和筛选过程没有分离.
2.这样写的后果使Company变成了一个失血模型而不是领域模型.
3.换查询条件的话,上面除了"筛选"一句有变化外其它都是模板代码,重复性很高.

真正符合OO的查询应该是这样:
  // OO化查询
  MemberFilter filter1=new MemberFilter(){
   public boolean accept(Member member) {
        return member.isMale() && member.getAge()>22;
   }
  };
 
  List ls=company.listMembers(filter1);

这段代码成功的把查询条件作为一个接口分离了出去,接口代码如下:
public interface MemberFilter{
 public boolean accept(Member member);
}

而类Company增加了这样一个函数:
 public List listMembers(MemberFilter memberFilter){
  List retval=new ArrayList();
 
  for(Iterator it=members.iterator();it.hasNext();){
   Member member=(Member)it.next();
  
   if(memberFilter.accept(member)){
    retval.add(member);
   }
  } 
 
  return retval;
 }

这就把模板代码归结到了类内部,外面不会重复书写了.Company也同时拥有了数据和行为,而不是原来的数据容器了.

四."查表"结构
这种结构将多个分支语句变换为一个查表结构,这样做对扩充程序结构,修改具体数额都很方便,使程序更易于维护.还可以把归结出的表结构放在持久介质中如
XML文件,数据库等,用到的时候再取,这样做在条件变化时不需要修改程序.

原始代码(VB代码,但应该不妨碍理解):
Dim count1
count1 = salary.Value + USA.Value * Drate + JAN.Value * Jrate - 4000
If count1 < 500 Then
 tax.Value = count1 * 0.05
ElseIf count1 < 2000 Then
 tax.Value = count1 * 0.1 - 25
ElseIf count1 < 5000 Then
 tax.Value = count1 * 0.15 - 125
ElseIf count1 < 20000 Then
 tax.Value = count1 * 0.2 - 375
ElseIf count1 < 40000 Then
 tax.Value = count1 * 0.25 - 1375
ElseIf count1 < 60000 Then
 tax.Value = count1 * 0.3 - 3375
Else
 tax.Value = count1 * 0.3 - 3375
End If

变换如下:
这是个税率计算的语句段,公式是确定的:税=月薪*税率-折扣,税率又和月薪有关系,月薪越高税率越高,首先这里可以归纳出一个基本类:
public class TaxItem{
 float limit; // 月薪界限
 float ratio;// 税率
 float discount;// 折扣

 public TaxItem(float limit,float ratio,float discount){
  this.limit=limit;
  this.ratio=ratio;
  this.discount=discount;
 }

 public TaxItem(){
  this(0.0f,0.0f,0.0f);
 }

 public float getDiscount() {
  return discount;
 }

 public float getLimit() {
  return limit;
 }

 public float getRatio() {
  return ratio;
 }
}

然后就是税计算类:
import java.util.ArrayList;

public class TaxCaculator{
        private static ArrayList list=new ArrayList();
       
        public TaxCaculator(){
                // 这里把各个等级加入到链表中,注意添加顺序是由小到大
                list.add(new TaxItem(500.0f,0.05f,0.0f));
                list.add(new TaxItem(2000.0f,0.1f,25.0f));
                list.add(new TaxItem(5000.0f,0.15f,125.0f));
                list.add(new TaxItem(20000.0f,0.2f,375.0f));
                list.add(new TaxItem(40000.0f,0.25f,1375.0f));
                list.add(new TaxItem(60000.0f,0.3f,3375.0f));
        }
       
        // 这个函数用来计算所得税
        public float getTax(float salary){
                TaxItem item=new TaxItem();
               
                for(int i=0;i<list.size();i++){
                        item=(TaxItem)list.get(i);
                       
                        if(salary>item.getLimit()){
                                continue;
                        }
                        else{
                                break;
                        }
                }              
               
                // 返回最终结果,当然,这个公式也可以放在TaxItem 类中,这里就见仁见智了。
                return salary*item.getRatio()-item.getDiscount();
        }
}

// 调用方法如下
public class Inlet{
        public static void main(String[] arg){
                TaxCaculator taxCaculator=new TaxCaculator();
               
                float salary=1000.f;   
                System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary));
               
                salary=2000.f; 
                System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary));
               
                salary=3000.f; 
                System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary));
        }
}

五."分而治之"结构
该结构将分支语句的执行部分分散到单独的类中处理,降低了系统耦合度,程序也更容易维护.

举例如下:
在日常工作中,我们经常需要解析一段字符串并交由相应的函数进行处理,例如TCP/IP通信中的命令解析和用户自定义文件解析等场合,通常的处理方法是这样:

if(命令==”AAA”){
    函数AAA执行;
}
else if(命令==”BBB”){
    函数BBB执行;
}
.
.
.
else{
    函数XXX执行;
}

这种方法在命令较少时是有效的,当命令众多时,if语句和相关的函数将会形成一个巨集,给检查,维护和扩充带来了很大的不便,久而久之将会成为系统性能提升的瓶颈。

一个成功的软件程序必须尽可能简单并易于重构和扩展,在命令模式和Java反射机制的帮助下,我们可以从容解决上述问题,达到简单并易于重构和扩展的要求。以下将简要说明解决方案。

1. 制作一个命令的抽象接口.
public interface Command{
       public abstract void execute(String[] args);
}

2. 让每种命令都实现这个接口.
// 命令一
public class CommandType01 implements Command{
       public void execute(String[] args){
               System.out.println("\n commandType01 start!");          
               System.out.print("\t commandType01 Length="+args.length);               
               System.out.println("\n commandType01 End!");
       }
}

// 命令二
public class CommandType02 implements Command{
       public void execute(String[] args){
               System.out.println("\n commandType02 start!");          
               
               System.out.print("\t commandType02 is:");               
               for(String item:args){
                       System.out.print("\t "+item);
               }
               
               System.out.println("\n commandType02 End!");
       }
}

// 命令三
public class CommandType03 implements Command{
       public void execute(String[] args){
               System.out.println("\n commandType03 start!");          
               System.out.print("\t commandType03 last Nation="+args[args.length-1]);          
               System.out.println("\n commandType03 End!");
       }
}

让每种命令都实现execute接口的用意是强制每个命令的执行方式一致,简化调用时的处理,但执行内容应该根据实际情况决定.
例如
命令一的执行内容是输出参数的个数
命令二的执行内容是输出参数的内容
命令二的执行内容是输出最后一个参数

3. 将命令防置到命令中心中去
命令中心类的代码如下:
public class Mediation{
       Command cmmd;// 命令对象的引用
       String[] cmmdArgs;// 参数列表
       
       public Mediation(){
               
       }
       
       public void fetchCommand(String strCmmd){
               cmmdArgs=strCmmd.split("\s+");// 分析原始命令
               
               String className="Command"+cmmdArgs[0];// 根据分析后命令的第一个参数得到类名
               
               try{
                       Class cls=Class.forName(className);// 利用反射机制得到类
                       cmmd=(Command)cls.newInstance();// 由类得到类实例
               }
               catch(Exception ex){
                       ex.printStackTrace();
               }               
       }       

       
       public void executeCommand(){
               cmmd.execute(cmmdArgs);// 执行命令对象的execute方法
       }

}

4.综合
public class Inlet {
       public static void main(String[] arg) {
               Mediation mediation = new Mediation();
               // 取得命令一并执行
               mediation.fetchCommand("Type01  AB CD");
               mediation.executeCommand();

               // 取得命令二并执行
               mediation.fetchCommand("Type02  1 2 3 4");
               mediation.executeCommand();

               // 取得命令三并执行
               mediation.fetchCommand("Type03  USA  Russia China");
               mediation.executeCommand();
       }
}

执行效果如下:
commandType01 start!
        commandType01 Length=3
commandType01 End!

commandType02 start!
        commandType02 is:       Type02  1       2       3       4
commandType02 End!

commandType03 start!
        commandType03 last Nation=China
commandType03 End!

由上可见,我们使用反射机制消除了庞大的分支语句,把命令的执行过程分散到了Command的各个子类中,降低了命令类和控制中心类的耦合程度,达到了简单并易于重构和扩展的要求。如果新增一种命令,只需增加Command的一个子类就可以了。
很多情况下命令的execute函数需要命令中心类或者其它类的信息,这时可以在Command接口类和Command的子类中间添加一个类CommandBase,在其中包含一个命令中心类或者其它类的引用,并增加相应的getter/setter函数,Command的子类继承这个类并实现Command的接口即可,最后在fetchCommand函数中传入中心类或者其它类的引用即可。

注意:这里对命令和Command的子类类名有特殊要求,即一种命令对应一种子类,子类类名可以由命令的首个参数简单组合而来,否则还是避免不了分支语句。

 

 


评论 / 个人网页 / 扔小纸条
* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 


 

分类小组论坛
杂谈 , 娱乐、八卦 , 文学、艺术 , 体育 , 旅游、同城 , 象牙塔 , 情感 , 时尚、生活 , 星座 , 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定