<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    PC的blog

    Finding... Thinking... Solving...

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      9 Posts :: 0 Stories :: 54 Comments :: 0 Trackbacks

    2008年8月4日 #

    本文緊接使用重構(gòu)移除丑陋的if else代碼(4)

    上篇文章談到如何能夠徹底把這個(gè)switch也移除掉呢?很簡單,我們只需要在getSystemStatePerformer()方法被調(diào)用之前先創(chuàng)建所有 performer匿名類的實(shí)例,然后在該方法被調(diào)用時(shí)直接返回對(duì)應(yīng)的實(shí)力。 如何具體實(shí)現(xiàn)呢? 用Map, 請(qǐng)看代碼:

    package de.jingge.refactoring;

     

    import static de.jingge.refactoring.SystemState.*;

    import java.awt.Image;

    import java.awt.image.BufferedImage;

    import java.lang.reflect.Method;

    import java.util.Collections;

    import java.util.HashMap;

    import java.util.Map;

     

    /**

     *

     * 
    @author gejing@gmail.com

     
    */

    public class SystemStatePerformerFactory {

     

    private static SystemStatePerformerFactory INSTANCE = new SystemStatePerformerFactory();

       

        
    private Map<SystemState, SystemStatePerformer> performers;

     

        
    private SystemStatePerformerFactory() {

    }

     

        
    public static SystemStatePerformerFactory getInstance() {

            
    return INSTANCE;

        }

       

        
    private synchronized Map<SystemState, SystemStatePerformer> getPerformers()

                
    throws Exception {

            
    if (performers == null) {

                performers 
    = new HashMap<SystemState, SystemStatePerformer>();

                
    // call all @FactoryMethod using reflection

                
    for (Method m : getClass().getDeclaredMethods()) {

                    
    if (m.getAnnotation(FactoryMethod.class!= null) {

                        SystemStatePerformer p 
    = (SystemStatePerformer) m.invoke(

                                
    thisnew Object[]{});

                        performers.put(p.getState(), p);

                    }

                }

                
    // make it readonly

                performers 
    = Collections.unmodifiableMap(performers);

            }

            
    return performers;

        }

     

        
    public SystemStatePerformer getSystemStatePerformer(SystemState state) throws Exception{

            
    return getPerformers().get(state);

        }

     

    @FactoryMethod

        
    private SystemStatePerformer createLoggedInPerformer() {

            
    return new SystemStatePerformer(LOGGEDIN, getImage("loggedin.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after logging in is successful,

                    
    // for example: show welcome dialog, open the last edit document, etc.

                }

            };

        }

     

    @FactoryMethod

        
    private SystemStatePerformer createLoggedOutPerformer() {

            
    return new SystemStatePerformer(LOGGEDOUT, getImage("loggedout.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after logging out is successful,

                    
    // for example: free used resource, dispose GUI components, etc.            }

                }

            };

        }

     

    @FactoryMethod

        
    private SystemStatePerformer createIdlePerformer() {

            
    return new SystemStatePerformer(IDLE, getImage("idle.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after the user is idle,

                    
    // for example: save the application state temporarily, lock the application, etc.

                }

            };

        }

     

        
    private Image getImage(String string) {

            
    return new BufferedImage(1010, BufferedImage.TYPE_4BYTE_ABGR);

        }

    }

    從代碼中可以看出,當(dāng)getPerformers()方法被第一次調(diào)用時(shí),我們會(huì)為每一個(gè)performer匿名類創(chuàng)建一個(gè)實(shí)例,并且將它們納入Map的管 理之中,以后每次調(diào)用的時(shí)候,直接從Map里面提取對(duì)應(yīng)某個(gè)狀態(tài)的performer就可以了, switch可以舍棄了。 @FactoryMethod這個(gè)注釋是我自己寫的,使用它主要是為了避免每次新增加一個(gè)create***Performer()方法后,都必須修改 getSystemStatePerformer()。

    @FactoryMethod的代碼如下:

    package de.jingge.refactoring;

     

    import java.lang.annotation.ElementType;

    import java.lang.annotation.Retention;

    import java.lang.annotation.RetentionPolicy;

    import java.lang.annotation.Target;

     


    @Retention(RetentionPolicy.RUNTIME)

    @Target({ElementType.METHOD})

    public @interface FactoryMethod {


    }

    到這里整個(gè)重構(gòu)已經(jīng)結(jié)束了, 我們已經(jīng)將if else, switch完全從代碼里剔除了。

    讀過Refactoring to Patterns這本書的朋友可能會(huì)覺得,這里所作的一些和書中第七章最后一節(jié)Replace Conditional Dispatcher with Command完全一樣。 Well,第一眼看上去確實(shí)很像,但是看完我寫的所有代碼后,再仔細(xì)想一想,兩者還是有區(qū)別的(Refactoring to Patterns這本書寫的非常好,對(duì)此書,我可以說是愛不釋手,還曾經(jīng)寫過一篇書評(píng)。事實(shí)上,我這篇文章正式基于這本書的):

    1. Factory + annonymous類而不是每一個(gè)狀態(tài)一個(gè)具體的實(shí)體類。

        這樣處理問題, 類的數(shù)量大大減少,類關(guān)聯(lián)的復(fù)雜程度也大大減少,維護(hù)起來很方便。

    2. performer并不單單是一個(gè)command,它擁有狀態(tài),并且可以處理更多的邏輯。


    全文完。
    posted @ 2008-08-04 03:48 polygoncell 閱讀(4623) | 評(píng)論 (37)編輯 收藏

    本文緊接使用重構(gòu)移除丑陋的if else代碼(3)

    OK, 到目前為止,所有的邏輯代碼已經(jīng)從SystemManager重構(gòu)到了SystemStatePerformer。下一步應(yīng)該繼續(xù)重構(gòu)SystemManager, 將SystemState替換為performer:

    1, 使用IDE的重構(gòu)功能,將變量SystemState改為SystemStatePerformer

    2. 在updateState()方法中調(diào)用SystemStatePerformerFactory

    3. 在測(cè)試代碼里面,調(diào)用manager.statePerformer.getState()

    重構(gòu)后的代碼如下:

    package de.jingge.refactoring;

     

    import static de.jingge.refactoring.SystemState.*;


    public class SystemManager {

     

        SystemStatePerformer statePerformer;

     

        
    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(SystemState state) {

            
    this.statePerformer = SystemStatePerformerFactory.getInstance()

                    getSystemStatePerformer(state);

            statePerformer.perform();

        }

    }

    可以看到if else已經(jīng)消失了。


    測(cè)試代碼也要做相應(yīng)修改:
    package de.jingge.refactoring;

     

    import org.junit.AfterClass;

    import org.junit.BeforeClass;

    import org.junit.Test;

    import static org.junit.Assert.*;

    import static de.jingge.refactoring.SystemState.*;


    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.statePerformer.getState(), LOGGEDIN);

        }

        @Test
        
    public void logout() {

            manager.logout();

            assertEquals(manager.statePerformer.getState(), LOGGEDOUT);

        }

        @Test
        
    public void idle() {

            manager.idle();

            assertEquals(manager.statePerformer.getState(), IDLE);

        }

    }

    到這里重構(gòu)已經(jīng)差不多完成了,代碼已經(jīng)更加面向?qū)ο罅恕_@里還有一個(gè)小問題,在factory里面還有一個(gè)switch,這個(gè)和if else其實(shí)是沒有本質(zhì)區(qū)別的,也就是說if else并沒有被完全移除掉。


    那么如何能夠徹底把這個(gè)switch也移除掉呢?很簡單,我們只需要在getSystemStatePerformer()方法被調(diào)用之前先創(chuàng)建所有 performer匿名類的實(shí)例,然后在該方法被調(diào)用時(shí)直接返回對(duì)應(yīng)的實(shí)力。 那么具體如何實(shí)現(xiàn)呢,請(qǐng)看下一篇文章使用重構(gòu)移除丑陋的if else代碼(5)
    posted @ 2008-08-04 03:08 polygoncell 閱讀(1936) | 評(píng)論 (1)編輯 收藏

    本文緊接使用重構(gòu)移除丑陋的if else代碼(2)

    移除if else

    首先仔細(xì)觀察一 下updateState()方法,我們會(huì)發(fā)現(xiàn),導(dǎo)致該方法內(nèi)存在大量if else的原因是它的參數(shù)僅僅是一個(gè)enum。由于enum本身并不含有任何邏輯代碼,因此導(dǎo)致處理enum的方法需要使用if else來分析enum然后調(diào)用相應(yīng)的邏輯。明白了這個(gè)道理之后,重構(gòu)的方向就明了了。簡單的說,我們需要要將方法參數(shù)由enum替換成一個(gè)更加強(qiáng)壯的抽 象類,每一個(gè)繼承該類的子類將具體負(fù)責(zé)處理一個(gè)enum實(shí)例,之后再將updateState()方法中相應(yīng)的邏輯代碼轉(zhuǎn)移到這些子類中。這樣處理之后, 令人討厭的if else就會(huì)消失了。


    我們將這個(gè)替換enum的抽象類命名為SystemStatePerformer,代碼如下:

    package de.jingge.refactoring;

     

    import java.awt.Image;


    public abstract class SystemStatePerformer {

        
    private final SystemState state;

        
    private Image image;

        
    public SystemStatePerformer(SystemState state, Image image) {

            
    this.state = state;

            
    this.image = image;

        }

        
    public SystemState getState() {

            
    return state;

        }

        
    public Image getImage() {

            
    return image;

        }
        
        
    public abstract void perform();

    }

    從代碼中可以看出,每 一個(gè)performer都含義有一個(gè)SystemState,這個(gè)SystemState屬性,將只能通過構(gòu)建器映射方式射入一個(gè)performer的對(duì) 象實(shí)例。換句話說SystemState只是一個(gè)只讀屬性,而且每一個(gè)performer實(shí)體類都只負(fù)責(zé)處理一個(gè)enum的實(shí)例(下面馬上會(huì)解釋如何實(shí)現(xiàn) 的)。這里使用的Image作為一個(gè)例子,它表示用戶的每一個(gè)狀態(tài)都可以使用一個(gè)圖標(biāo)來表示。performer()方法將負(fù)責(zé)處理具體的邏輯。這個(gè) SystemStatePerformer的實(shí)體子類可以引用任何類型的對(duì)象,然后在perform()方法里面進(jìn)行調(diào)用。




    下 一步就是編寫SystemStatePerformer的實(shí)體子類。我首先想到的是為每一個(gè)enum實(shí)例編寫一個(gè)實(shí)際的子類,理論上來說是沒問題的,但是 這樣做必須編寫一大堆的子類,不便于管理。所以我決定使用Factory + annonymous classes來構(gòu)建具體的實(shí)體子類,讓Factory來管理所有的實(shí)體子類。 代碼如下:

    package de.jingge.refactoring;

     

    import static de.jingge.refactoring.SystemState.*;

    import java.awt.Image;

    import java.awt.image.BufferedImage;


    public class SystemStatePerformerFactory {

     

    private static SystemStatePerformerFactory INSTANCE = new SystemStatePerformerFactory();

       

        
    private SystemStatePerformerFactory() {

    }

     

        
    public static SystemStatePerformer getSystemStatePerformer(SystemState state) {

            
    switch (state) {

                
    case LOGGEDIN:

                    
    return createLoggedInPerformer();

                
    case IDLE:

                    
    return createIdlePerformer();

                
    case LOGGEDOUT:

                    
    return createLoggedOutPerformer();

                
    default:

                    
    throw new IllegalAccessError("Unkonw status");

            }

        }

     

        
    private static SystemStatePerformer createLoggedInPerformer() {

            
    return new SystemStatePerformer(LOGGEDIN, getImage("loggedin.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after logging in is successful,

                    
    // for example: show welcome dialog, open the last edit document, etc.

                }

            };

        }

     

        
    private static SystemStatePerformer createLoggedOutPerformer() {

            
    return new SystemStatePerformer(LOGGEDOUT, getImage("loggedout.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after logging out is successful,

                    
    // for example: free used resource, dispose GUI components, etc.            }

                }

            };

        }

     

        
    private static SystemStatePerformer createIdlePerformer() {

            
    return new SystemStatePerformer(IDLE, getImage("idle.gif")) {

     

                @Override

                
    public void perform() {

                    
    // do something after the user is idle,

                    
    // for example: save the application state temporarily, lock the application, etc.

                }

            };

        }

     

        
    private static Image getImage(String string) {

            
    return new BufferedImage(1010, BufferedImage.TYPE_4BYTE_ABGR);

        }

    }

    從 代碼中可以看到,針對(duì)每一個(gè)enum狀態(tài)都有一個(gè)創(chuàng)建performer的方法,該方法返回一個(gè)匿名類。邏輯代碼將會(huì)被轉(zhuǎn)移至個(gè)匿名類的 perform()方法之內(nèi)。整個(gè)Factory只有一個(gè)公開的方 法:getSystemStatePerformer(SystemState),SystemManager可以調(diào)用這個(gè)方法來獲得相應(yīng)的 Performer實(shí)例。


    在 這篇文章中,我希望專屬于if else的問題。對(duì)于其他設(shè)計(jì)方面的問題,我采取的態(tài)度是能省略就省略。實(shí)際開發(fā)中,還有有很多問題需要處理,例如,使用static方法會(huì)導(dǎo)致系統(tǒng)的可 測(cè)試性下降,在實(shí)際開發(fā)中應(yīng)該盡量避免,解決這類問題的方法之一是使用DI框架,例如Google Guice。

    下一篇文章使用重構(gòu)移除丑陋的if else代碼(4)繼續(xù)講解。
    posted @ 2008-08-04 02:54 polygoncell 閱讀(2245) | 評(píng)論 (4)編輯 收藏

    本文緊接使用重構(gòu)移除丑陋的if else代碼(1)

    使用Enum替換int常量

    這一步比較簡單,先創(chuàng)建一個(gè)enum類:

    package de.jingge.refactoring;

    public enum SystemState {

        LOGGEDIN,

        LOGGEDOUT,

        IDLE;

    }


    然后開始重構(gòu)SystemManager, 使用SystemState代替SystemManager里的int狀態(tài):

       1. 添加 import static de.jingge.refactoring.SystemState.*;
       2. 刪除所有的integer常量  
       3. 將變量state的類型改為SystemState.

    代碼如下:



    package de.jingge.refactoring;

    import static de.jingge.refactoring.SystemState.*;

    public class SystemManager {

        SystemState 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(SystemState 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;
        }
    }

    然后重構(gòu)測(cè)試類:

    1.    添加import static de.jingge.refactoring.SystemState.*;
    2.    刪除所有常量前引用的SystemManager.

    package de.jingge.refactoring;

    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;
    import static org.junit.Assert.*;
    import static de.jingge.refactoring.SystemState.*;


    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, LOGGEDIN);
        }
      
        @Test
        
    public void logout() {
            manager.logout();
            assertEquals(manager.state, LOGGEDOUT);
        }

        @Test
        
    public void idle() {
            manager.idle();
            assertEquals(manager.state, IDLE);
        }
    }


    運(yùn)行這個(gè)測(cè)試類->通過

    下一篇文章使用重構(gòu)移除丑陋的if else代碼(3)開始處理if else hell
    posted @ 2008-08-04 02:45 polygoncell 閱讀(2092) | 評(píng)論 (0)編輯 收藏

    我們知道因?yàn)榫幊陶Z言的限制,歷史遺留下來的系統(tǒng)總是有很多的毛病,不夠面向?qū)ο螅绕涫呛芏嘞到y(tǒng)濫用if else。我曾經(jīng)見過一個(gè)項(xiàng)目,大家基本上就是寫一個(gè)方法,然后在里面if else套if esle得嵌套了好幾層,難看就不必說了,這種代碼根本就沒法維護(hù)。

    今天我就使用從實(shí)際項(xiàng)目中提煉出來的例子來講解一下如何將這類代碼變得更加面向?qū)ο?- 重構(gòu)成模式并且添加測(cè)試代碼,

    先來看一個(gè)丑陋的類:

    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;

        }

    }


    這里我們展示了一個(gè) SystemManager,它負(fù)責(zé)處理用戶在系統(tǒng)中的狀態(tài):登入(logged in),登出(logged out),以及空閑(idle)。從代碼中可以看到,這個(gè)類用了int來定義狀態(tài)并且因此導(dǎo)致了updatteState()方法里面出現(xiàn)大量if else。從目前看來這些if else是無法避免的,應(yīng)為這個(gè)類需要針對(duì)不同的狀態(tài)作出反應(yīng)。隨著狀態(tài)的增加,if else的數(shù)量也會(huì)繼續(xù)增加。這個(gè)解決方案顯然很差。

    那么怎么樣才能讓這個(gè)類更加地面向?qū)ο竽兀?br id="i7km89" />
    在處理面向?qū)ο笾埃覀兪紫纫帉懸粋€(gè)測(cè)試類,這也是處理這類歷史遺留下來代碼所必需做的第一步,只有在測(cè)試代碼的保護(hù)下,我們才能放心大膽地進(jìn)行重構(gòu)。

    初步的測(cè)試代碼如下:

    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);

        }

    }

    運(yùn)行測(cè)試代碼->通過。

    在下一篇文章我們將正式開始重構(gòu)。地址:使用重構(gòu)移除丑陋的if else代碼(2)
    posted @ 2008-08-04 02:36 polygoncell 閱讀(2701) | 評(píng)論 (3)編輯 收藏

    主站蜘蛛池模板: 亚洲一级特黄大片在线观看| 97青青草原国产免费观看| 无码天堂亚洲国产AV| 色五月五月丁香亚洲综合网| 亚洲国产精品99久久久久久| 亚洲精品美女久久久久久久| 亚洲日韩久久综合中文字幕| 亚洲日韩AV无码一区二区三区人| 亚洲老熟女五十路老熟女bbw| 亚洲国产精华液2020| 国产成人亚洲综合在线| 深夜久久AAAAA级毛片免费看| 国产日韩精品无码区免费专区国产| 国产成人无码免费网站| 免费无码又爽又刺激网站| 久久免费视频99| 久久免费看黄a级毛片| 一二三四影视在线看片免费| 精品无码国产污污污免费| 亚洲av区一区二区三| 亚洲热妇无码AV在线播放| 亚洲黄色免费观看| 亚洲国产成a人v在线观看 | 四色在线精品免费观看| 国产成人精品免费视频大全五级| 免费一级毛片在级播放| 中文字幕无码精品亚洲资源网| 亚洲国产第一站精品蜜芽| 久久精品国产亚洲AV高清热| 亚洲色欲啪啪久久WWW综合网| 亚洲AV日韩AV无码污污网站| h视频免费高清在线观看| 国产精品免费观看调教网| www.999精品视频观看免费| 国产又粗又长又硬免费视频| 亚洲精品高清国产一线久久| 7777久久亚洲中文字幕蜜桃| 亚洲人成网站在线在线观看| 九九热久久免费视频| 四虎在线免费视频| 亚洲 另类 无码 在线|