Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 306|回复: 0

[Java基础知识]为你的程序锦上添花的五种程序组织形式

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-2 12:59:33 | 显示全部楼层 |阅读模式
    形式一."见兔撒鹰".
                                                                                        
       如果有一个类有一个集合成员,可以在为此成员添加元素时再把具体集合建立起来,以免浪费空间和时间. 例:
      
       
         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
       
        形式二."只管结果,不顾过程"

      从集合中取区间元素时,可以直接从上下限之间取来,让try...catch...去处理越界的事. 题设:有个数不定元素的列表(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...比较贴近人类思维.
    形式三."奉旨行事"
       在查询中,如果把查询条件和遴选过程分开来更有益,程序也因此解耦合.这才是OO化的查询. 需求:从公司的职员列表中,找出男性且年龄大于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
       
          这种写法没有错,但是不是面向对象的写法,它有以下缺陷:
    1.查询条件和筛选过程没有分离.
    2.这样写的后果使Company变成了一个失血模型而不是领域模型.
    3.换查询条件的话,上面除了"筛选"一句有变化外其它都是模板代码,重复性很高. 真正符合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也同时拥有了数据和行为,而不是原来的数据容器了. 形式四."化繁为简"
        这种结构将多个分支语句变换为一个查表结构,这样做对扩充程序结构,修改具体数额都很方便,使程序更易于维护.还可以把归结出的表结构放在持久介质中如XML文件,数据库等,用到的时候再取,这样做在条件变化时不需要修改程序. 原始代码(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));
       
      形式五."分而治之"
        该结构将分支语句的执行部分分散到单独的类中处理,降低了系统耦合度,程序也更容易维护. 举例如下:
    在日常工作中,我们经常需要解析一段字符串并交由相应的函数进行处理,例如TCP/IP通信中的命令解析和用户自定义文件解析等场合,通常的处理方法是这样:  if(命令==”AAA”){
         函数AAA执行;
    }
    else if(命令==”BBB”){
         函数BBB执行;
    }
    .
    .
    .
    else{
         函数XXX执行;
    }  这种方法在命令较少时是有效的,当命令众多时,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(
        "
       
    commandType01 start!
        "
        );           

         5
                       System.out.print(
        "
                 commandType01 Length=
        "
        +
        args.length);               

         6
                       System.out.println(
        "
       
    commandType01 End!
        "
        );

         7
               }

         8
        }

         9
       

        10
       
        //
         命令二
       

        11
       
        public
         
        class
         CommandType02
        implements
         Command{

        12
               
        public
         
        void
         execute(String[] args){

        13
                       System.out.println(
        "
       
    commandType02 start!
        "
        );           

        14
                        

        15
                       System.out.print(
        "
                 commandType02 is:
        "
        );               

        16
                      
        for
        (String item:args){

        17
                               System.out.print(
        "
                 
        "
        +
        item);

        18
                       }

        19
                        

        20
                       System.out.println(
        "
       
    commandType02 End!
        "
        );

        21
               }

        22
        }

        23
       

        24
       
        //
         命令三
       

        25
       
        public
         
        class
         CommandType03
        implements
         Command{

        26
               
        public
         
        void
         execute(String[] args){

        27
                       System.out.println(
        "
       
    commandType03 start!
        "
        );           

        28
                       System.out.print(
        "
                 commandType03 last Nation=
        "
        +
        args[args.length
        -
        1
        ]);           

        29
                       System.out.println(
        "
       
    commandType03 End!
        "
        );

        30
               }

        31
        }

        32
       

        33
       
       
    让每种命令都实现execute接口的用意是强制每个命令的执行方式一致,简化调用时的处理,但执行内容应该根据实际情况决定.
    例如
    命令一的执行内容是输出参数的个数
    命令二的执行内容是输出参数的内容
    命令三的执行内容是输出最后一个参数  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
        }
       
    4.执行过程
       
         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
       
        执行效果如下:
    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的子类类名有特殊要求,即一种命令对应一种子类,子类类名可以由命令的首个参数简单组合而来,否则还是避免不了分支语句。  以上五种组织形式,若加以灵活运用,相信能减少一些代码臭味.
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 22:09 , Processed in 0.372038 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表