设计模式之委派模式

文章目录

  • 前言
  • 正文
    • 一、生活中的例子
    • 二、Java代码实现
      • [2.1 类设计](#2.1 类设计)
      • [2.2 代码实现](#2.2 代码实现)
        • [2.2.1 Employee](#2.2.1 Employee)
        • [2.2.2 ArchitectureDesignEmployer](#2.2.2 ArchitectureDesignEmployer)
        • [2.2.3 BackEmployer](#2.2.3 BackEmployer)
        • [2.2.4 FrontEmployer](#2.2.4 FrontEmployer)
        • [2.2.5 Leader](#2.2.5 Leader)
        • [2.2.6 EmployeeStrongPointEnum](#2.2.6 EmployeeStrongPointEnum)
        • [2.2.7 Boss](#2.2.7 Boss)
      • [2.3 测试](#2.3 测试)
        • [2.3.1 Client](#2.3.1 Client)
        • [2.3.2 测试结果](#2.3.2 测试结果)
    • 三、委派模式的优缺点
      • [3.1 优点](#3.1 优点)
      • [3.2 缺点](#3.2 缺点)

前言

委派模式(Delegate Pattern)又叫委托模式,是一种面向对象的设计模式。它不属于23种设计模式之中,但同样也应用广泛。

熟悉java类加载的人都知道,java有一个双亲委派模型。就是应用了这个委派模式的思想。(但这不是我写本文的原因!)

委派模式允许对象组合实现与继承相同的代码重用。它的基本作用就是负责任务的调用和分配任务,是一种特殊的静态处理代理,可以理解为全权代理。

PS:写本文的原因在于,前几天看SpringMVC源码时遇到过。DispatcherServlet 的作用就是调节,分派请求。最终使用HandlerMapping来处理这些请求。关于这个可以参考文章:《SpringMVC原理(设计原理+启动原理+工作原理)》 的相关内容。

正文

一、生活中的例子

以生活中的例子,来研究何为委派模式。首先看一下这张图:

一个简单的模式,老板派发任务到经理,经理做协调,委派任务到各个不同岗位的人员。

二、Java代码实现

在第一小节中的例子,使用java代码对其进行设计并实现。

2.1 类设计

本次类的设计,使用类图展示。

2.2 代码实现

创建一个简单的java项目,本次使用java8。

项目结构如下:

2.2.1 Employee
java 复制代码
package org.feng;

/**
 * 员工
 *
 * @author feng
 */
public interface Employee {

    /**
     * 处理任务接口
     *
     * @param task 任务
     */
    void handle(String task);
}
2.2.2 ArchitectureDesignEmployer
java 复制代码
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));
    }
}
2.2.3 BackEmployer
java 复制代码
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));
    }
}
2.2.4 FrontEmployer
java 复制代码
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));
    }
}
2.2.5 Leader
java 复制代码
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();
    }
}
2.2.6 EmployeeStrongPointEnum
java 复制代码
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;
    }
}
2.2.7 Boss
java 复制代码
package org.feng;

/**
 * 老板
 *
 * @author feng
 */
public class Boss {

    /**
     * 委派任务到经理
     *
     * @param task   任务
     * @param leader 经理
     */
    public void delegateTask(String task, Leader leader) {
        leader.handle(task);
    }
}

2.3 测试

2.3.1 Client
java 复制代码
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);
    }
}
2.3.2 测试结果
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

我是架构设计师,我擅长【架构优化,架构设计】!
现在开始处理【架构设计】任务!
我是前端开发人员,我擅长【平面设计,页面修改,页面调整】!
现在开始处理【页面修改】任务!
这个任务【测试页面功能】,俺做不来!

三、委派模式的优缺点

3.1 优点

通过任务委派能够将一个大型的任务细化,然后通过统一管理这些子任务的完成情况实现任务的跟进,能够加快任务执行的效率。

3.2 缺点

任务委派方式需要根据任务的复杂程度进行不同的改变,在任务比较复杂的情况下可能需要进行多重委派,容易造成絮乱。

相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616884 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端