1. 程式人生 > >設計模式之委派模式(java實現)

設計模式之委派模式(java實現)

委派模式(delegate):並不屬於23種設計模式,但是面向物件常用的一種設計模式,而且在SpringMVC原始碼中有大量使用。這種模式原理就是類 B和類 A 是兩個互相沒有任何關係的類,B 具有和 A 一模一樣的方法和屬性;並且呼叫 B 中的方法,屬性就是呼叫 A 中同名的方法和屬性。B 好像就是一個受 A 授權委託的中介。第三方的程式碼不需要知道 A 的 存在,也不需要和 A 發生直接的聯絡,通過 B 就可以直接使用 A 的功能,這樣既能夠使用到 A 的各種功能,又能夠很好的將 A 保護起來了,一舉兩得。也是一種行為型的設計模式。

舉一個生活化的例子,例如公司中三個層級員工,執行員工staff,專案經理manager,老闆boss,老闆將相對應的任務和目標和專案經理溝通,他並不關心執行員工staff執行的情況,只需要重manager這裡瞭解專案進展和結果,專案經理manager將具體專案拆解或者分配給相對應的員工去執行,這種情況就類似一種委派模式。

下面就按照上述這種方式簡單的用程式碼來實現舉例一下:

首先是類圖:

員工類StuffA,StuffB實現介面Stuff,專案經理manager,將具體任務進行分配執行,Boss是直接呼叫manger下達命令

具體實現:

Stuff介面:

package Delegate.company;

public interface Stuff {
    public void doing(String command);
}

StuffA:

package Delegate.company;

public class StuffA implements Stuff {
    @Override
    public void doing(String command) {
        System.out.println("我是員工A,我現在開始幹" + command + "工作");

    }
}

StuffB: 

package Delegate.company;

public class StuffB implements Stuff {
    @Override
    public void doing(String command) {
        System.out.println("我是員工B,我現在開始幹" + command + "工作");

    }
}

Manager:

package Delegate.company;

import java.util.HashMap;
import java.util.Map;

public class Manager  {
    private Map<String,Stuff> targets = new HashMap<String,Stuff>();

    public Manager() {
        targets.put("加密",new StuffA());
        targets.put("登入",new StuffB());
    }

    public void doing(String command){
        targets.get(command).doing(command);
    }
}

Boss呼叫:

package Delegate.company;

public class Boss {
    public static void main(String[] args) {
        Manager manager = new Manager();
        manager.doing("加密");
        manager.doing("登入");
        
    }

}

執行結果:

以上是一個簡單的委派模式實現的方式。委派模式中委派者(manager)要持有被委派者(staff)的引用。可以看到在實際實現中和代理模式以及策略模式稍微有點相似。實際上可以這樣理解:代理模式注重的是過程,委派模式注重的是結果,策略模式注重的是可擴充套件(外部擴充套件),委派模式注重的是內部的靈活和複用。委派模式的核心是分發,排程,派遣。委派模式可以看做是靜態代理和策略模式的一種特殊組合。

在實際的Sping中有大量使用到委派模式,在Spring中以Delegate,Dispatcher結尾的類名中,就使用到了委派模式。

下面以簡化的ServletDispatcher舉例:


public class ServletDispatcher {

    private List<Handler> handlerMapping = new ArrayList<Handler>();

    public ServletDispatcher(){
        try {
            Class<?> memberActionClass = MemberAction.class;
            handlerMapping.add(new Handler()
                    .setController(memberActionClass.newInstance())
                    .setMethod(memberActionClass.getMethod("getMemberById", new Class[]{String.class}))
                    .setUrl("/web/getMemberById.json"));
        }catch(Exception e){

        }
    }



    public void doService(HttpServletRequest request, HttpServletResponse response){
        doDispatch(request,response);
    }


    private void doDispatch(HttpServletRequest request, HttpServletResponse response){

        //1、獲取使用者請求的url
        //   如果按照J2EE的標準、每個url對對應一個Serlvet,url由瀏覽器輸入
       String uri = request.getRequestURI();

        //2、Servlet拿到url以後,要做權衡(要做判斷,要做選擇)
        //   根據使用者請求的URL,去找到這個url對應的某一個java類的方法

        //3、通過拿到的URL去handlerMapping(我們把它認為是策略常量)
        Handler handle = null;
        for (Handler h: handlerMapping) {
            if(uri.equals(h.getUrl())){
                handle = h;
                break;
            }
        }

        //4、將具體的任務分發給Method(通過反射去呼叫其對應的方法)
        Object object = null;
        try {
            object = handle.getMethod().invoke(handle.getController(),request.getParameter("mid"));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //5、獲取到Method執行的結果,通過Response返回出去
//        response.getWriter().write();

    }


    class Handler{

        private Object controller;
        private Method method;
        private String url;

        public Object getController() {
            return controller;
        }

        public Handler setController(Object controller) {
            this.controller = controller;
            return this;
        }

        public Method getMethod() {
            return method;
        }

        public Handler setMethod(Method method) {
            this.method = method;
            return this;
        }

        public String getUrl() {
            return url;
        }

        public Handler setUrl(String url) {
            this.url = url;
            return this;
        }
    }


}

在上面這個程式碼中,使用者通過url請求過來可以看做是之前例子中的boss,ServletDispatcher可以看做是之前例子中的manager,實際執行的Handler可以看做是stuff。

熟悉了委派模式,對分析學習SpringMVC原始碼有好處。