带你撸出一手好代码
以子类代替对类型码的条件判断

随着代码的演变,属于同一个类的不同方法中会出现相同形式的if条件判断,这些条件判断的判断条件相同、分支数量相同,不同的是每个分支中执行的代码。 另外,这些if条件判断的条件多数是不同值的类型码。这种类的代码结构被简化后大致模板如下

 

public class Main {

    public static class Example {
        public static final int A = 1;
        public static final int B = 2;
        public static final int C = 3;
 
        int typeCode;
 
        public Example(int typeCode)
        {
            this.typeCode = typeCode;
        }
 
        public String getValue()
        {
            switch (typeCode)
            {
                case A:
                    return "A";
                case B:
                    return "B";
                case C:
                    return "C";
                default :
                    return "D";
            }
        }
 
        public String getValue1()
        {
            switch (typeCode)
            {
                case A:
                    return "A1";
                case B:
                    return "B1";
                case C:
                    return "C1";
                default:
                    return "D1";
            }
        }
    }
 
 
 
    public static void main(String[] args) {
        Example example = new Example(Example.A);
        System.out.println(example.getValue());
        System.out.println(example.getValue1());
 
        example = new Example(Example.B);
        System.out.println(example.getValue());
        System.out.println(example.getValue1());
    }
}


getValue和getValue1两个方法中有着相同形式的条件判断

 

 switch (typeCode)
            {
                case A:
                    do something
                case B:
                   do something
                case C:
                    do something
                default:
                    do something
            }


 这种形式的代码并不容易维护,假如要为此类再增加一个方法getValue2, 也就意味着此if条件判断结构又将被拷贝一份

       

 public String getValue2()
        {
            switch (typeCode)
            {
                case A:
                    return "A2";
                case B:
                    return "B2";
                case C:
                    return "C2";
                default:
                    return "D2";
            }
        }
    }


与此同时,如果需求变动,比如说要增加一个类型码扩展这些if判断,那么这些散布在类四处的if条件判断都需修改,显然这不是一件愉快的事情。 其次,这个类的职责似乎显得过重了, 类中多个方法会根据相同条件判断中不同的分支完成不同的工作, 换言之,在类中的这一系列条件判断有多少分支就表示这个类需要做多少件事情,这违反了面向对象程序设计单一职责的设计原则。

 

有一种解决方案叫做以子类代替对类型码的条件判断的手段可以解决这个问题,使代码保持良好的结构以及可维护性。

 

这种方法建议将在不同方法中相同条件判断分支中的代码分离到不同的类中, 也就是说把原本完成多件事情的类分割成多个小类,每个类只负责做一件事情。

 

以上面的代码为例, 我们新增4个类,它们都继承至原有的Example类,然后重写getValue方法和getValue1方法

 

public class ExampleDefault extends Example {
        @Override
        public String getValue() {
            return "";
        }
 
        @Override
        public String getValue1() {
            return "";
        }
    }
 
    public class ExampleA extends Example {
        @Override
        public String getValue() {
            return "A";
        }
 
        @Override
        public String getValue1() {
            return "A1";
        }
    }
 
    public class ExampleB extends Example {
        @Override
        public String getValue() {
            return "B";
        }
 
        @Override
        public String getValue1() {
            return "B1";
        }
    }
 
    public class ExampleC extends Example {
        @Override
        public String getValue() {
            return "C";
        }
 
        @Override
        public String getValue1() {
            return "C1";
        }
    }


每一个类拥有原Example的getValue和getValue1方法的其中一个条件分支的代码。 再把Example类改成抽象类,将getValue和getValue1修改成抽象方法。

 

 public abstract class Example {
        public static final int A = 1;
        public static final int B = 2;
        public static final int C = 3;
 
        public abstract String getValue();
 
        public abstract String getValue1();
}


接下来这一步至关重要, 我们为Example添加一个静态方法,这个方法集中了之前分散在各处的if条件判断

   

 public abstract class Example {
        public static final int A = 1;
        public static final int B = 2;
        public static final int C = 3;
 
        public abstract String getValue();
 
        public abstract String getValue1();
 
        public static Example Create(int typeCode)
        {
            switch (typeCode)
            {
                case A:
                    return new ExampleA();
                case B:
                    return new ExampleB();
                case C:
                    return new ExampleC();
                default:
                    return new ExampleDefault();
            }
        }
    }


然后以这种方式调用


    public static void main(String[] args) {
        Example example = Example.Create(Example.A);
        System.out.println(example.getValue());
        System.out.println(example.getValue1());
 
        example = Example.Create(Example.B);
        System.out.println(example.getValue());
        System.out.println(example.getValue1());
    }



修改后的代码,虽然类的数量以及代码量增加了,但显然条理清晰了许多。 假如我们要增加一种条件判断,只需要增加一个新的继承自Example的类型,然后再在Create方法中添加一个条件分支, 而原有的代码几乎不用改动,这极大的减少了代码被改出BUG的几率, 也符合面向对象的一种设计原则:类应该对扩展开放,对修改关闭


作者:陈大侠
日期:2018-02-04

留言(0条)

我要发表留言

您的大名 选填
电子邮箱 选填

欢迎关注微信公众号 「带你撸出一手好代码」

首页    GitHub 知乎 豆瓣 博客园