在读到《代码整洁之道》里面说“使用多态代替if else和switch”的时候,刚好想到我们项目中有大量使用switch的情况,导致项目代码显得杂乱不堪,整个类超过1500行,刚接触这些代码的时候看得我想吐,试着能不能对代码进行一下重构,其中也碰到了一些问题,在此记录下来。
1.多条件的一般处理方式(使用switch)
现在考虑有这样一种简单场景,需要我们根据性别和年纪来找到合适的称呼。
<span style="font-size:18px;">/**
* 性别
*/
public enum Sex {
FEMALE,
MALE
}</span><span style="font-size:18px;">/**
* 年龄分类
*/
public enum Age {
YOUNG,
ADULT,
OLD
}</span><span style="font-size:18px;">public class Person {
private Sex sex;
private Age age;
//setter,getter,构造函数
}</span>那给定一个Person,找到合适的称呼,可以写出如下代码:<span style="font-size:18px;">public class MakeDecision {
public static void main(String[] args) {
Person person = new Person(Sex.FEMALE, Age.YOUNG);
Age age = person.getAge();
Sex sex = person.getSex();
switch (sex) {
case FEMALE:
switch (age) {
case YOUNG:
System.out.println("小女孩");
break;
case ADULT:
System.out.println("中年妇女");
break;
case OLD:
System.out.println("老太婆");
break;
default:
break;
}
break;
case MALE:
switch (age) {
case YOUNG:
System.out.println("小男孩");
break;
case ADULT:
System.out.println("怪蜀黍");
break;
case OLD:
System.out.println("老头儿");
break;
default:
break;
}
}
}
}</span>这样符合我们的一般思维,下面用多态代替。
2.多态的形式
<pre name="code" class="java"><span style="font-size:18px;">/**
* 基类
*/
public class Person {
private Sex sex;
private Age age;
public void print() {
}
// setter,getter
}</span><span style="font-size:18px;">public class LittleGirl extends Person {
@Override
public void print() {
System.out.println("小女孩");
}
}</span><span style="font-size:18px;">public class Madam extends Person {
@Override
public void print() {
System.out.println("中年妇女");
}
}</span>.......
那么问题来了,这样对于给定的Person,虽然使用了多态,是不是还是无法避免进行条件判断?你可能写出的代码如下:
<span style="font-size:18px;">public class MakeDecision {
public static void main(String[] args) {
Person person = new Person();
person.setAge(Age.YOUNG);
person.setSex(Sex.FEMALE);
// 重构版本
Person person1 = matchPerson(person);
person1.print();
}
private static Person matchPerson(Person person) {
Age age = person.getAge();
Sex sex = person.getSex();
switch (sex) {
case FEMALE:
switch (age) {
case YOUNG:
return new LittleGirl();
case ADULT:
return new Madam();
case OLD:
return new OldLady();
}
case MALE:
//其他男人的称呼
}
return new LittleGirl();
}
}</span>对于这种组合条件的判断,使用多态还是无法避免条件判断,唯一的好处是,如果对于条件组合很多的情况,可以将各自的处理逻辑隔离开来,我们这里举例处理逻辑就只有一句System,out.println,但是真正情况可能包含更多判断和操作,只有做之后,就可以将这些判断和操作,分发到各自的子类当中去(此例中的LittleGirl、Madam等的print函数中)。
3.更多的尝试
为了解决上面的疑问,利用map和表驱动法来解决,不知道有没有更好的方案。
<span style="font-size:18px;">public class MakeDecision {
private static final String[] table = { "littlegirl", "madam", "oldlady" };
private static final Map<String, Person> map = new HashMap<String, Person>();
static {
map.put("littlegirl", new LittleGirl());
map.put("madam", new Madam());
map.put("oldlady", new OldLady());
}
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Person();
person.setAge(Age.YOUNG);
person.setSex(Sex.FEMALE);
String key = choose(person);
Person p = map.get(key);
p.print();
}
private static String choose(Person person) {
String key = null;
Sex sex = person.getSex();
Age age = person.getAge();
int orderInTable = 0;
for (Sex t : Sex.values()) {
for (Age s : Age.values()) {
if (s.equals(sex) && t.equals(age)) {
return table[orderInTable];
}
orderInTable++;
}
}
return key;
}
}</span>这里的驱动表需要Sex和Age的顺序想对应,即:
Sex : 1 FEMALE 2MALE
Age : 1 YOUNG 2 ADULT 3 OLD
则table的第一需要是littlegirl,第二个需要是madam,第三个是oldlady,也和choose函数的循环有关,是Sex在外层,Age在内层,才会出现这样的顺序。
版权声明:本文为sanniao原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。