Java設計模式(5)之責任鏈模式學習總結

boker_han發表於2017-10-26
    在日常生活中,我們如果仔細觀察的話,很多事情都蘊含著責任鏈模式的思想;比如某個人去售樓處買房,對銷售人員提出打折的要求,如果折扣比較 
小,銷售人員有權給予該購買者提出的折扣優惠,就可以直接答應該請求;如果折扣過大,銷售人員無權答應,則會想他的上司——銷售組長詢問, 
如果銷售組長有權答應該折扣,則直接回復可以,並將房子售賣給客戶;以此類推,直至該折扣請求被處理,客戶得到相應的答覆,該事件結束。

    再比如,我們曾經玩過的拋手絹、擊鼓傳花等遊戲,都有責任鏈模式的影子;總的來說,責任鏈模式就是:將接收者物件連城一條鏈,將對應的請求
在該鏈上進行傳遞,直至有接收者物件處理了該請求;這種通過允許更多接收者物件有機會對請求進行處理,來避免請求者和接收者之間的耦合; 
    其中,責任鏈模式中的“責任鏈”源於在鏈上的每個處理者都有責任去處理在鏈上傳遞的請求,同時,處理者對應不同等級的請求,相應地有處理請求
的許可權;
    另外,在上面的例子中,購房者不需要知道誰處理了他的折扣請求,擊鼓傳花中,擊鼓者,也不需要知道是誰拿到花並進行節目表演,這就解釋了 
上面說的請求者和接收處理者之間的去耦合是怎麼一回事。  

    下面將以生活中公司中職員請假的流程作為示例,採用責任鏈模式進行程式碼的設計,通過直觀的講解來闡述責任鏈模式的設計思想;
    package com.pattern.handler;
    /**
     * 假期申請接收者對應的抽象類,負責處理工作人員的假期申請
     */
    public abstract class LeaveHandler
    {
        /**
         * 直接後繼管理人員,用於傳遞請求
         */
        protected LeaveHandler successor;

        public void setSuccessor(LeaveHandler successor) 
        {
            this.successor = successor;
        }
        /**
         * 處理假期申請
         */
        public abstract void processLeave(int days);
    }


    package com.pattern.handler;
    /**
     * 組長類, 可以批准2天以內的假期申請
     */
    public class GroupLeader extends LeaveHandler 
    {
        @Override
        public void processLeave(int days) 
        {
            if(days<=2)
            {
                System.out.println(this.getClass().getName()+"批准了"+days+"天假");
            }
            else
            {
                successor.processLeave(days);
            }
        }
    }


    package com.pattern.handler;
    /**
     * 副主任類, 可以批准3天以內的假期申請
     */
    public class ViceManager extends LeaveHandler 
    {
        @Override
        public void processLeave(int days) 
        {
            if(days<=3)
            {
                System.out.println(this.getClass().getName()+"批准了"+days+"天假");
            }
            else
            {
                successor.processLeave(days);
            }
        }
    }


    package com.pattern.handler;
    /**
     * 主任類, 可以批准5天以內的假期申請
     */
    public class Manager extends LeaveHandler {
        @Override
        public void processLeave(int days) 
        {
            if(days<=5)
            {
                System.out.println(this.getClass().getName()+"批准了"+days+"天假");
            }
            else
            {
                successor.processLeave(days);
            }
        }
    }


    package com.pattern.handler;
    /**
     * 總經理類,可以批准10天以內的假期申請
     * 假期超過10天, 就拒絕申請
     */
    public class GeneralManager extends LeaveHandler {
        @Override
        public void processLeave(int days) 
        {
            if(days<=10)
            {
                System.out.println(this.getClass().getName()+"批准了"+days+"天假");
            }
            else
            {
                System.out.println(this.getClass().getName()+"不批准"+days+"天假");
            }
        }
    }


    package com.pattern.handler;
    public class LeaveHandlerFactory {
        /**
         * 建立LeaveHandler的工廠方法
         */
        public static LeaveHandler createPriceHandler() 
        {
            LeaveHandler gl = new GroupLeader();
            LeaveHandler vm = new ViceManager();
            LeaveHandler m = new Manager();
            LeaveHandler gm = new GeneralManager();

            gl.setSuccessor(vm);
            vm.setSuccessor(m);
            m.setSuccessor(gm);

            return gl;
        }
    }


    package com.pattern;
    import java.util.Random;
    import com.pattern.handler.LeaveHandler;
    import com.pattern.handler.LeaveHandlerFactory;
    /**
     * 工作人員,申請假期
     */
    public class Client {
        private LeaveHandler leaveHandler;
        public void setLeaveHandler(LeaveHandler leaveHandler) 
        {
            this.LeaveHandler = leaveHandler;
        }
        public void requestLeave(int days)
        {
            leaveHandler.processLeave(days);
        }
        public static void main(String[] args)
        {
            Client client = new Client();  
            client.setLeaveHandler(LeaveHandlerFactory.
            createLeaveHandler());
            Random random = new Random();
            for(int i=1;i<=100;i++){
                System.out.print(i+":");
                client.requestLeave(random.nextInt(20));
            }   
        }
    }
    程式碼重點分析:
    ①抽象類LeaveHandler包含一個自身型別的資料域,這個資料域的別名叫做責任鏈上的後繼者,當本類的物件無權處理請求時,就將該請求傳遞 
給該資料域對應的物件進行處理,這一點非常重要,是形成責任鏈的關鍵所在!
    ②抽象類LeaveHandler屬於Java中泛指的介面,這裡使用抽象類作為介面,體現了面向介面程式設計的思想,這一點要注意!
    ③這裡將不同型別的處理者的產生交由工廠類LeaveHandlerFactory來完成,體現了物件導向(OO)中類設計的單一職責原則,即對於某一 
介面或類,只把該介面或類的相關方法放進該介面或類中。同時,Java的命名規範要求我們設計類或介面時,能夠見名知意,每一個類的類名必須 
代表著該類的語義!
    ④通過分析上述程式碼,可以發現職員類只和import com.pattern.handler.LeaveHandler以及import com.pattern.handler.LeaveHandlerFactory兩個類相關聯, 
並沒有和繼承於抽象類LeaveHandler的具體類相關聯,這就帶來了業務變更時, 
無需修改介面,只需要增加繼承於LeaveHandler的類即可;比如,當公司中等級變化時(對應管理人員的等級有所增加),可以通過再設計一個 
對應類,並在工廠類中進行該類物件的獲取,並將其嵌入責任鏈中,即可實現該專案仍可以正常工作,這就體現了設計模式應對不同場景時獨具 
的優勢,體現了專案的可擴充套件性!
    在責任鏈模式中存在著一些缺點,就本例來說:
    ①當請假的天數較少,只需要經過一個或者少數的處理者就可以處理該請求,那麼這就造成之後的處理者被建立出來,但是並沒有參與業務 
處理,造成時間和空間上的浪費。
    ②當多個職員請假時,需要分別建立一組管理人員物件,這就造成了不必要的開銷,其實,只需一組管理人員物件即可處理多名職員的請假請求。
    責任鏈模式在Java的前端或者後臺開發中也會常常遇到,比如後端開發中遇到的異常處理機制、Java Web中的過濾器鏈;
前端開發中的JavaScript中的事件觸發處理過程,都蘊含了責任鏈模式的設計思想!

相關文章