我们知道因为编程语言的限制,历史遗留下来的系统总是有很多的毛病,不够面向对象,尤其是很多系统滥用if else。我曾经见过一个项目,大家基本上就是写一个方法,然后在里面if else套if esle得嵌套了好几层,难看就不必说了,这种代码根本就没法维护。
今天我就使用从实际项目中提炼出来的例子来讲解一下如何将这类代码变得更加面向对象 - 重构成模式并且添加测试代码, 
先来看一个丑陋的类:
package de.jingge.refactoring;
 
public class SystemManager {
 
    public static final int LOGGEDIN = 0;
    public static final int LOGGEDOUT = 1;
    public static final int IDLE = 2;
    int state;
 
    public void login() {
        // call service#login()
        updateState(LOGGEDIN);
    }
   
    public void logout() {
        // call service#logout()
        updateState(LOGGEDOUT);
    }
   
    public void idle() {
        // call some other services
        updateState(IDLE);
    }
    public void updateState(int state) {
        if (state == LOGGEDIN) {
            // do something after logging in is successful,
            // for example: show welcome dialog, open the last edit document, etc.
        } else if (state == LOGGEDOUT) {
            // do something after logging out is successful,
            // for example: free used resource, dispose GUI components, etc.
        } else if (state == IDLE) {
            // do something after the user is idle,
            // for example: save the application state temporarily, lock the application, etc.
        } else {
            throw new IllegalArgumentException("unknown state");
        }
        this.state = state;
    }
}
这里我们展示了一个 SystemManager,它负责处理用户在系统中的状态:登入(logged in),登出(logged
out),以及空闲(idle)。从代码中可以看到,这个类用了int来定义状态并且因此导致了updatteState()方法里面出现大量if
else。从目前看来这些if else是无法避免的,应为这个类需要针对不同的状态作出反应。随着状态的增加,if
else的数量也会继续增加。这个解决方案显然很差。
那么怎么样才能让这个类更加地面向对象呢?
在处理面向对象之前,我们首先要编写一个测试类,这也是处理这类历史遗留下来代码所必需做的第一步,只有在测试代码的保护下,我们才能放心大胆地进行重构。
初步的测试代码如下:
package de.jingge.refactoring;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class SystemManagerTest {
    private static SystemManager manager;
    @BeforeClass
    public static void setUpClass() throws Exception {
        manager = new SystemManager();
        // add some service mock objects
    }
    @AfterClass
    public static void tearDownClass() throws Exception {
    }
    @Test
    public void login() {
        manager.login();
        assertEquals(manager.state, SystemManager.LOGGEDIN);
    }
    @Test
    public void logout() {
        manager.logout();
        assertEquals(manager.state, SystemManager.LOGGEDOUT);
    }
    @Test
    public void idle() {
        manager.idle();
        assertEquals(manager.state, SystemManager.IDLE);
    }
}
运行测试代码->通过。
在下一篇文章我们将正式开始重构。地址:
使用重构移除丑陋的if else代码(2)
声明:本文版权归作者所有,如需转载请注明出处。