委派模式(Delegate Pattern)又叫委托模式,是一种面向对象的设计模式。它不属于23种设计模式之中,但同样也应用广泛。
熟悉java类加载的人都知道,java有一个双亲委派模型。就是应用了这个委派模式的思想。(但这不是我写本文的原因!)
委派模式允许对象组合实现与继承相同的代码重用。它的基本作用就是负责任务的调用和分配任务,是一种特殊的静态处理代理,可以理解为全权代理。
PS:写本文的原因在于,前几天看SpringMVC源码时遇到过。
DispatcherServlet
的作用就是调节,分派请求。最终使用HandlerMapping
来处理这些请求。关于这个可以参考文章:《SpringMVC原理(设计原理+启动原理+工作原理)》 的相关内容。
以生活中的例子,来研究何为委派模式。首先看一下这张图:
一个简单的模式,老板派发任务到经理,经理做协调,委派任务到各个不同岗位的人员。
在第一小节中的例子,使用java代码对其进行设计并实现。
创建一个简单的java项目,本次使用java8。
项目结构如下:
package org.feng;
/**
* 员工
*
* @author feng
*/
public interface Employee {
/**
* 处理任务接口
*
* @param task 任务
*/
void handle(String task);
}
package org.feng;
import java.util.Set;
/**
* 架构设计师
*
* @author feng
*/
public class ArchitectureDesignEmployer implements Employee {
@Override
public void handle(String task) {
printWords();
System.out.printf("现在开始处理【%s】任务!%n", task);
}
private void printWords() {
Set<String> strongPointSet = EmployeeStrongPointEnum.getStrongPointSet(this.getClass());
System.out.printf("我是架构设计师,我擅长【%s】!%n", String.join(",", strongPointSet));
}
}
package org.feng;
import java.util.Set;
/**
* 后端开发人员
*
* @author feng
*/
public class BackEmployer implements Employee {
@Override
public void handle(String task) {
printWords();
System.out.printf("现在开始处理【%s】任务!%n", task);
}
private void printWords() {
Set<String> strongPointSet = EmployeeStrongPointEnum.getStrongPointSet(this.getClass());
System.out.printf("我是后端开发人员,我擅长【%s】!%n", String.join(",", strongPointSet));
}
}
package org.feng;
import java.util.Set;
/**
* 前端开发人员
*
* @author feng
*/
public class FrontEmployer implements Employee {
@Override
public void handle(String task) {
printWords();
System.out.printf("现在开始处理【%s】任务!%n", task);
}
private void printWords() {
Set<String> strongPointSet = EmployeeStrongPointEnum.getStrongPointSet(this.getClass());
System.out.printf("我是前端开发人员,我擅长【%s】!%n", String.join(",", strongPointSet));
}
}
package org.feng;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
/**
* 经理
*
* @author feng
*/
public class Leader implements Employee {
private static final Map<String, Employee> EMPLOYEE_MAP;
static {
EMPLOYEE_MAP = new HashMap<>(16);
try {
initEmployeeMap();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public void handle(String task) {
if (!EMPLOYEE_MAP.containsKey(task)) {
System.out.printf("这个任务【%s】,俺做不来!%n", task);
return;
}
// 经理委派任务到其他员工
EMPLOYEE_MAP.get(task).handle(task);
}
private static void initEmployeeMap() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
EmployeeStrongPointEnum[] strongPoints = EmployeeStrongPointEnum.values();
for (EmployeeStrongPointEnum strongPoint : strongPoints) {
Class<? extends Employee> employeeClass = strongPoint.getEmployeeClass();
Employee employee = employeeClass.getDeclaredConstructor().newInstance();
TreeSet<String> strongPointSet = strongPoint.getStrongPoints();
for (String str : strongPointSet) {
EMPLOYEE_MAP.put(str, employee);
}
}
EMPLOYEE_MAP.forEach((k, v) -> {
System.out.println("EMPLOYEE_MAP: task = " + k + ", emp = " + v);
});
System.out.println();
}
}
package org.feng;
import java.util.*;
/**
* 员工强项枚举
*
* @author feng
*/
public enum EmployeeStrongPointEnum {
ARCHITECTURE_DESIGN_EMPLOYER_STRONG_POINT(ArchitectureDesignEmployer.class, "架构设计", "架构优化"),
FRONT_EMPLOYER_STRONG_POINT(FrontEmployer.class, "平面设计", "页面修改", "页面调整"),
BACK_EMPLOYER_STRONG_POINT(BackEmployer.class, "数据库设计", "后端功能开发", "后端功能修改");
private final Class<? extends Employee> employeeClass;
private final String[] strongPoints;
EmployeeStrongPointEnum(Class<? extends Employee> employeeClass, String... strongPoints) {
this.employeeClass = employeeClass;
this.strongPoints = strongPoints;
}
public Class<? extends Employee> getEmployeeClass() {
return employeeClass;
}
public TreeSet<String> getStrongPoints() {
return new TreeSet<>(Arrays.asList(strongPoints));
}
private static final Map<Class<? extends Employee>, TreeSet<String>> EMP_STRONG_POINT_CACHE_MAP = new HashMap<>();
static {
for (EmployeeStrongPointEnum strongPointEnum : EmployeeStrongPointEnum.values()) {
EMP_STRONG_POINT_CACHE_MAP.put(strongPointEnum.getEmployeeClass(), strongPointEnum.getStrongPoints());
}
}
public static Set<String> getStrongPointSet(Class<? extends Employee> employeeClass) {
TreeSet<String> treeSet = EMP_STRONG_POINT_CACHE_MAP.get(employeeClass);
if(treeSet == null || treeSet.isEmpty()) {
return Collections.emptySet();
}
return treeSet;
}
}
package org.feng;
/**
* 老板
*
* @author feng
*/
public class Boss {
/**
* 委派任务到经理
*
* @param task 任务
* @param leader 经理
*/
public void delegateTask(String task, Leader leader) {
leader.handle(task);
}
}
package org.feng;
/**
* 测试
*
* @author feng
*/
public class Client {
public static void main(String[] args) {
Boss boss = new Boss();
Leader leader = new Leader();
boss.delegateTask("架构设计", leader);
boss.delegateTask("页面修改", leader);
boss.delegateTask("测试页面功能", leader);
}
}
EMPLOYEE_MAP: task = 后端功能开发, emp = org.feng.BackEmployer@448139f0
EMPLOYEE_MAP: task = 页面修改, emp = org.feng.FrontEmployer@7cca494b
EMPLOYEE_MAP: task = 页面调整, emp = org.feng.FrontEmployer@7cca494b
EMPLOYEE_MAP: task = 架构设计, emp = org.feng.ArchitectureDesignEmployer@7ba4f24f
EMPLOYEE_MAP: task = 平面设计, emp = org.feng.FrontEmployer@7cca494b
EMPLOYEE_MAP: task = 后端功能修改, emp = org.feng.BackEmployer@448139f0
EMPLOYEE_MAP: task = 架构优化, emp = org.feng.ArchitectureDesignEmployer@7ba4f24f
EMPLOYEE_MAP: task = 数据库设计, emp = org.feng.BackEmployer@448139f0
我是架构设计师,我擅长【架构优化,架构设计】!
现在开始处理【架构设计】任务!
我是前端开发人员,我擅长【平面设计,页面修改,页面调整】!
现在开始处理【页面修改】任务!
这个任务【测试页面功能】,俺做不来!
通过任务委派能够将一个大型的任务细化,然后通过统一管理这些子任务的完成情况实现任务的跟进,能够加快任务执行的效率。
任务委派方式需要根据任务的复杂程度进行不同的改变,在任务比较复杂的情况下可能需要进行多重委派,容易造成絮乱。