设计模式 | 挑战委派模式

621 阅读3分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

委派模式,它不属于GOF23种常见模式,它允许对象组合实现与继承相同的代码重用。

一、定义

委派是一种使组合具有与继承一样强大的复用能力的方法。在委派中,处理请求涉及两个对象: 接收对象将操作委派给其委派对象,这类似于将请求延迟到父类的子类。

委派模式代理模式很相似,可以看做是一种特殊情况下的静态代理的全权代理。两种模式有本质的区别,代理模式注重过程,而委派模式注重结果。

两者的区别说的很抽象,具体来说:

  • 委派模式大致的流程是:你找我,我作为中间人,我不干事,我又根据你的需求/命令去找别人处理。这里强调一个权衡选择的过程。
  • 代理模式大致的流程是:你想办一件事情,明确的知道找A就能完成,但是你不找A,你找A的代理人去处理,实际上A的代理人还是去找A去办理的。

委派模式基本的作用就是负责任务的调用和分配任务。在Java生态中,Spring框架就用到了委派模式,哪个地方呢,就是大家熟知的DispatcherServlet。一般来说类名上使用了DelegatingDispathcer单词,大概率也就用到了委派模式。

二、代码实现

这里构想一个干工程的公司,公司里面有Boss、Manager、Worker等角色,Worker具体细分了电工ElectWorker,木工 WoodWorker等。

有一个场景,老板发送个指令给经理,让经理去安排电工或木工的活。

首先要创建工人的抽象接口,接口中包含描述工人的工种性质,以及工人执行干活的操作。

public interface Worker {
​
    /**
     * 干事的工种类型
     * @return 工种类型
     */
    String  workType();
​
    /**
     * 干事当然是干事情
     */
    void doingJob(String command);
}

然后具体实现木工和电工。

public class WoodWorker implements Worker{
    /**
     * 干事的工种类型
     *
     * @return 工种类型
     */
    @Override
    public String workType() {
        return "WoodWorker";
    }
​
    /**
     * 干事当然是干事情
     */
    @Override
    public void doingJob(String command) {
        System.out.println("i am WoodWorker,receive command【 " + command + "】,start to work");
    }
}
​
public class ElectWorker implements Worker{
    /**
     * 干事的工种类型
     *
     * @return 工种类型
     */
    @Override
    public String workType() {
        return "ElectWorker";
    }
​
    /**
     * 干事当然是干事情
     */
    @Override
    public void doingJob(String command) {
        System.out.println("i am ElectWorker,receive command【 " + command + "】,start to work");
    }
}

管理工人的直接上级是经理。

public class Manager {
​
    final Map<String,Worker> scheduler = new HashMap<>();
​
    public Manager(){
        scheduler.put(WorkType.WOOD,new WoodWorker());
        scheduler.put(WorkType.ELECT,new ElectWorker());
    }
    public void doing(String command){
        scheduler.get(ANALYSIS_WORK_TYPE.apply(command)).doingJob(command);
    }
​
    /**
     * 分析命令的任务类型
     */
    static final Function<String,String>  ANALYSIS_WORK_TYPE = command->{
        if(command.contains(WorkType.WOOD)){
            return WorkType.WOOD;
        }else if(command.contains(WorkType.ELECT)){
            return WorkType.ELECT;
        }
        throw new UnsupportedOperationException();
    };
​
    interface  WorkType{
        String WOOD = "Wood";
        String ELECT = "Elect";
    }
​
}

经理管理了工人,通过scheduler 进行任务调度,他不是命令/任务的最终执行者,他会根据命令分析具体的任务类型,再安排具体的工人去干活。

管理经理的当然是老板,老板只是需要发号施令给经理,不需要知道任务具体是谁去执行。

public class Boss {
    public void command(String command,Manager manager){
        manager.doing(command);
    }
}

执行流程。

public class DelegatingApp {
    public static void main(String[] args) {
        new Boss().command("anybody Wood",new Manager());
        new Boss().command("anybody Elect",new Manager());
    }
}

执行后输出。

image-20210805152146864.png

整个程序UML类图如下

Delegating.png

三、总结

总的来说,使用委托模式,会让逻辑层次更加分明,各个角色的职责划分更加清晰,代码实现上也会优雅不少。但同时也要注意区分一下代理模式委派模式策略模式三者的区别。