設(shè)計(jì)模式-委派模式

委派模式

? 精簡程序邏輯,便于閱讀

? 其基本作用是負(fù)責(zé)任務(wù)的調(diào)度和分配任務(wù),和代理模式很像,可以看做是一種特殊情況下的靜態(tài)代理的全權(quán)代理,但是代理模式注重過程,但是委派模式注重結(jié)果

? 是一種行為型模式。

? 一般Delegate,Dispatcher結(jié)尾的都是委派

不屬于GOF23種設(shè)計(jì)模式

通用類圖

image-20210107152938301

Delegate 委派角色

負(fù)載在各個(gè)具體角色實(shí)例之間做出決策,并且判斷和調(diào)用具體的方法

Deletgate委派類,委派類收到任務(wù)后,交給對應(yīng)的集體干活的人事干活

public class Delegate implements Task{
  public void doTask() {
    System.out.println("代理執(zhí)行開始....");

    Task task = null;
    if (new Random().nextBoolean()){
      task = new ConcreteA();
      task.doTask();
    }else{
      task = new ConcreteB();
      task.doTask();
    }

    System.out.println("代理執(zhí)行完畢....");
  }
}

案例

老板叫員工干活

? 老板叫經(jīng)理干活,經(jīng)理通過不同的內(nèi)容叫不同的員工去做事情

image-20210107154330117

首先定義接口,把干活的內(nèi)容抽象出來

public interface IEmployee {
    public void doing(String command);

}

接下來定義員工a和員工B

public class EmployeeA implements IEmployee {
  @Override
  System.out.println("我是員工A,我現(xiàn)在開始干" + command + "工作");
}
}
public class EmployeeB implements IEmployee {
  @Override
  public void doing(String command) {
    System.out.println("我是員工B,我現(xiàn)在開始干" + command + "工作");
  }
}

經(jīng)理記錄員工

public class Leader implements IEmployee {

  private Map<String,IEmployee> targets = new HashMap<String,IEmployee>();

  public Leader() {
    targets.put("加密",new EmployeeA());
    targets.put("登錄",new EmployeeB());
  }

  //項(xiàng)目經(jīng)理自己不干活
  public void doing(String command){
    targets.get(command).doing(command);
  }

}

老板叫經(jīng)理干活

public class Boss {
  public void command(String command,Leader leader){
    leader.doing(command);
  }
}

測試

public class DelegateTest {
  public static void main(String[] args) {

    //客戶請求(Boss)、委派者(Leader)、被被委派者(Target)
    //委派者要持有被委派者的引用
    //代理模式注重的是過程, 委派模式注重的是結(jié)果
    //策略模式注重是可擴(kuò)展(外部擴(kuò)展),委派模式注重內(nèi)部的靈活和復(fù)用
    //委派的核心:就是分發(fā)、調(diào)度、派遣
    //委派模式:就是靜態(tài)代理和策略模式一種特殊的組合

    new Boss().command("登錄",new Leader());
  }
}

這種方式能夠避免我們使用if或者switch去判斷

可以看到老板其實(shí)并不需要關(guān)心干活的是誰,只需要找領(lǐng)導(dǎo)就行了,這個(gè)是符合最少知道原則的

在源碼中的應(yīng)用

Spring Web MVC

org.springframework.web.servlet.DispatcherServlet#doDispatch

不同的請求交給不同的請求處理器mappedHandler去處理

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  //勝率了很多源代碼

  // Determine handler for the current request.
  mappedHandler = getHandler(processedRequest);
  if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
  }

  // Determine handler adapter for the current request.
  HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());



  if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
  }

  // Actually invoke the handler.
  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

  if (asyncManager.isConcurrentHandlingStarted()) {
    return;
  }

  applyDefaultViewName(processedRequest, mv);
  mappedHandler.applyPostHandle(processedRequest, response, mv);
}

}

JDK-雙親委派

? 一個(gè)類加載器在加載類時(shí),先把這個(gè)請求委派給自己的父類加載器去執(zhí)行,如果父類加載器還存在父類加載器, 就繼續(xù)向上委派,直到頂層的啟動(dòng)類加載器。如果父類加載器能夠完成類加加載,就成功返回,如果父類加載器無法完成加載,那么子加載器オ會(huì)嘗試試自己去加載。

? 從定義中可以看到雙親加載模型一個(gè)類加載器加載類時(shí),首先不是自己加載,而是委派給父加載器。

? 下面我們來看看 ClassLoader#loadClass

protected Class<?> loadClass(String name, boolean resolve)
  throws ClassNotFoundException
{
  synchronized (getClassLoadingLock(name)) {
    // First, check if the class has already been loaded
    Class<?> c = findLoadedClass(name);
    if (c == null) {
      long t0 = System.nanoTime();
      try {
        if (parent != null) {
          c = parent.loadClass(name, false);
        } else {
          c = findBootstrapClassOrNull(name);
        }
      } catch (ClassNotFoundException e) {
        // ClassNotFoundException thrown if class not found
        // from the non-null parent class loader
      }

      if (c == null) {
        // If still not found, then invoke findClass in order
        // to find the class.
        long t1 = System.nanoTime();
        c = findClass(name);

        // this is the defining class loader; record the stats
        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
        sun.misc.PerfCounter.getFindClasses().increment();
      }
    }
    if (resolve) {
      resolveClass(c);
    }
    return c;
  }
}
if (parent != null) {
  c = parent.loadClass(name, false);
} else {
  c = findBootstrapClassOrNull(name);
}

先看父類有沒有,有的話就父來loadClass

反射-Method

public Object invoke(Object obj, Object... args)
  throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
  if (!override) {
    if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
      Class<?> caller = Reflection.getCallerClass();
      checkAccess(caller, clazz, obj, modifiers);
    }
  }
  MethodAccessor ma = methodAccessor;             // read volatile
  if (ma == null) {
    ma = acquireMethodAccessor();
  }
  return ma.invoke(obj, args);
}

可以看到全權(quán)交給了MethodAccessor來調(diào)用

sun.reflect.NativeMethodAccessorImpl#invoke

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
  if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
    MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
    this.parent.setDelegate(var3);
  }

  return invoke0(this.method, var1, var2);
}

metho沒干啥,委派給了別人來做,這樣我們不用關(guān)心底層是怎么用的

有點(diǎn)類似于門面模式,但是委派是行為型模式,門面是結(jié)構(gòu)型模式

Spring中的BeanDefinition

解析xml中的Bean標(biāo)簽也使用了委派模式

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

Element的話就交給BeanDefinitionParserDelegate來處理了

靜態(tài)代理會(huì)在前后增加一些邏輯,委派模式就是全權(quán)交給別人來處理

總結(jié)

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 通過任務(wù)委派能夠?qū)⒁粋€(gè)大型的任務(wù)細(xì)化,

    • 通過統(tǒng)一管理這些子任務(wù)的完成情況實(shí)現(xiàn)任務(wù)的跟進(jìn)
  • 能夠加快任務(wù)執(zhí)行的效率。

缺點(diǎn)

  • 任務(wù)委派方式需要根據(jù)任務(wù)的復(fù)雜程度進(jìn)行不同的改變
  • 在任務(wù)比較復(fù)雜的情況下可能需要進(jìn)行多重委派
  • 容易造成紊亂

和代理的區(qū)別

委派是行為型模式

代理是結(jié)構(gòu)型模式

  • 委派注重任務(wù)派遣
    • 注重結(jié)果
  • 代理注重增強(qiáng)
    • 注重過程
  • 委派是特殊的靜態(tài)代理,相當(dāng)于全權(quán)代理

我的筆記倉庫地址gitee 快來給我點(diǎn)個(gè)Star吧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容