设计模式之委派模式

文章目录

  • 前言
  • 正文
    • 一、生活中的例子
    • 二、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 缺点

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

相关推荐
这孩子叫逆7 分钟前
Spring Boot项目的创建与使用
java·spring boot·后端
星星法术嗲人10 分钟前
【Java】—— 集合框架:Collections工具类的使用
java·开发语言
黑不溜秋的24 分钟前
C++ 语言特性29 - 协程介绍
开发语言·c++
一丝晨光29 分钟前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
天上掉下来个程小白31 分钟前
Stream流的中间方法
java·开发语言·windows
刷帅耍帅42 分钟前
设计模式-享元模式
设计模式·享元模式
xujinwei_gingko42 分钟前
JAVA基础面试题汇总(持续更新)
java·开发语言
liuyang-neu44 分钟前
力扣 简单 110.平衡二叉树
java·算法·leetcode·深度优先
刷帅耍帅1 小时前
设计模式-模版方法模式
设计模式
sp_wxf1 小时前
Lambda表达式
开发语言·python