设计模式大作业:委派模式----不属于23种常用的设计模式

委派模式

    引言
    委派模式是一种在java中广泛应用的设计模式,但是其并不属于GOF中23种常用的设计模式。委派模式和曾经学过的代理模式很像,可以看做是代理模式的一种特殊形式,与此同时委派模式和策略模式也很相似。一般设计模式都是几种模式混合使用来解决一个问题,很少的情况会单独使用。
1 委派模式动机与定义
    委派模式跟代理模式和策略模式很像,可以将其看做是代理模式和策略模式的组合。代理模式是用一个类来代替另一个类来执行某些操作;策略模式是根据条件的不同选择不同的策略来完成某项任务。领导需要将某个具体任务指派给助理来完成,助理接到任务后,根据任务的具体情况,将任务分解,并将对应的任务分配给对应的下属员工,这就是委派模式。在代理模式中,代理需要亲自去完成需要完成的任务,而委派任务中助理只需要将任务分解后,分配给对应的员工即可。
    1.1 模式动机
    老板需要有一个开发项目需要完成,便将这个项目交给了项目经理,项目经理根据项目的请况,分为了前端项目和后端项目,分别交给了前端开发人员,后端开发人员去开发。项目经理在老板眼里是将这个项目完成了,但其实是苦逼的开发人员夜以继日的熬夜才将项目完成。下面是开发项目的代码示例:

public XiangMuJingLi {
    
    
    public void doWork(String workName) {
    
    
        if("前端开发".equals(workName)) {
    
    
            Worker qianDuan = new QianDuan("小明");
            qianDuan.doWork(workName);
        }
        if("后端开发".equals(workName)) {
    
    
            Worker houDuan = new HouDuan("小王");
            houDuan.doWork(workName);
        }
        System.out.println("开发项目完成");
    }
}

    当我们需要增加新的员工的时候,就违背了开闭原则。解决方案就是使用委派模式。委派模式就是将具体任务的实现细节隐藏,对外部来看就是项目经理完成了这个项目,实则是开发人员完成的。如图1所示。

在这里插入图片描述

图1 开发项目示意图

    在java开发过程中,会经常遇到委派模式,其中spring、mybatis等开源框架中使用了大量的委派模式。理解委派模式的实现原理可以很好地帮助理解这些框架的源码结构。委派模式的核心是委派类的实现。
    1.2 模式定义
    委派模式(Delegate Pattern)定义:委派类通过对象组合来实现与继承相同的代码逻辑,它的基本作用就是负责任务的调度和分配,是一种特殊的静态代理,可以理解为全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式属于行为型模式。
2 委派模式结构与分析
    2.1 模式结构
    委派模式结构图如图2所示。

在这里插入图片描述

图2 委派模式结构图

    委派模式包含如下角色:
    1.Worker(抽象员工类)
    抽象员工类声明了所有员工的抽象工作方法,提供一个外部的统一调用接口。这样一来对于客户端来说,不管是什么类型的工作,只要统一的调用接口中的方法就可以完成指定的任务。具体的任务完成操作在接口的实现类中进行区别,不同的工作进行不同的操作。
    2.Delegator(委派者角色)
    委派者角色内部的具体工作执行方法可以将客户端发来的具体任务进行分解,不同的工作任务,交给不同的员工。委派者通过将总任务细分成具体任务,分别给不同角色的员工来完成具体任务,最后组合起来就完成了总任务。委派模式向外部提供了一个工作执行的统一接口,工作完成的具体细节对外部是透明的。
    3.WorkerA(被委派者角色)
    被委派者角色是具体细分任务的执行者,他是用来完成一个大的总任务中的细节任务的实现。一个大的总任务一般情况下都是将其分解成具体的细节任务,并将其分配给具体负责这部分任务的员工来完成。委派者正是将细节任务委派给不同的被委派者共同协作完成任务的。
    2.2 模式分析
    委派模式是一种类的行为模式,他在java系统开发过程中是经常被使用的一中设计模式。在开源框架spring中,委派模式的身影随处可见。
    委派者模式向系统外部定义了一个统一的任务执行的接口,起具体任务的实现对外部完全透明。外部通过调用委派者的任务执行方法,委派者将任务细化,并委派给对应的任务执行角色去执行具体任务。这一切操作对外界来说都不可见,就好像委派者自己单独完成了这个任务。委派者看上去是位于客户端和具体任务执行者之间的中介,相当于是静态代理的一中特殊的情况:全权代理。实际上委派者只负责干调度的工作,分配任务。在分配任务之前,委派者要做一个权衡(选择),类似于策略模式,所以总体上来看,委派模式可以说是代理模式和策略模式的组合体。
    下面通过实例代码对该模式进行分析。首先定义一个抽象员工类,用来定义所有员工共同的工作调用方法,经典代码如下:

public interface Worker {
    
    
    public void doWork(String workName);
}

    抽象员工类中的doWork方法是员工用来执行具体任务workName的操作方法。
    被委派者实现抽象员工类,用来定义完成任务需要执行的具体操作,被委派者是任务的具体执行者。其经典代码如下:

public class WorkerA implements Worker {
    
    
    public void doWork(String workName) {
    
    
        System.out.println("工人A负责完成" + workName + "工作");
    }
}

    被委派者中定义了一个doWork方法,用来完成具体的工作,他是任务的真正执行者。根据不同员工的不同职责,可以设计不同的任务执行操作。
    委派者是将收到的任务命令进行分解。分别委派给对应可以处理细部操作的员工,其经典代码如下:

import java.util.*;
public class Delegator implements Worker {
    
    
    private HashMap workers = new HashMap();
	……
    public void doWork(String workName) {
    
    
        ((Worker)workers.get(workName)).doWork(workName);
    }
}

    委派者类中定义的doWork操作根据接受的workName参数,将具体的任务委派给可以处理对应任务的员工进行处理。
3 委派模式实例与解析
    3.1 委派模式实例之一行业务办理流程
    下面通过委派模式实现房地产项目的实例来进一步理解委派者模式。
    1. 实例说明
    某开发商有一个房地产项目需要建设,公司总经理将这个房地产项目交给了项目经理张三来完成,张三开始组织施工。其中有工程部员工李四进行现场土建施工,有工经部员工王五进行验工计价,有物资部员工赵六进行物资设备调度。三个部门在项目经理的合理调度下成功的完成了这个房地产项目。
    2. 实例类图
    通过分析,该实例类图如图3所示。
在这里插入图片描述

图3 房地产项目类图

    3. 实例代码及解释
    (1)抽象员工类Worker

public interface Worker {
    
    
    public void doWork(String workName);
}

    在抽象员工类Worker中定义了一个统一的工作执行的方法。它是项目经理、工程部、工经部、物资部这些员工共有的工作方法。
    (2)被委派者GongChengBu(工程部员工类)

public class GongChengBu implements Worker {
    
    
    private String name;
    public GongChengBu(String name){
    
    
        this.name = name;
    }
    public void doWork(String workName) {
    
    
        System.out.println("工程部:" + name + "完成" + workName + "工作");
    }
}

    在具体员工类中实现了抽象员工类中的方法,工程部调用doWork方法来完成土建施工的工作。
    (3)被委派者GongJingBu(工经部员工类)

public class GongJingBu implements Worker {
    
    
    private String name;
    public GongJingBu(String name){
    
    
        this.name = name;
    }
    public void doWork(String workName) {
    
    
        System.out.println("工经部:" + name + "完成" + workName + "工作");
    }
}

    在具体员工类中实现了抽象员工类中的方法,工经部调用doWork方法来完成验工计价的工作。
    (4)被委派者WuZiBu(物资部员工类)

public class WuZiBu implements Worker {
    
    
    private String name;
    public WuZiBu(String name){
    
    
        this.name = name;
    }
    public void doWork(String workName) {
    
    
        System.out.println("物资部:" + name + "完成" + workName + "工作");
    }
}

    在具体员工类中实现了抽象员工类中的方法,物资部调用doWork方法来完成物资设备调度的工作。
    (5)委派者类Worker(项目经理类)

import java.util.*;
public class XiangMuJingLi implements Worker {
    
    

    private String name;
    private HashMap workers = new HashMap();

    public XiangMuJingLi(String name){
    
    
        this.name = name;
    }

    public void add(String workName, Worker worker){
    
    
        workers.put(workName,worker);
    }

    public void remove(String workName){
    
    
        workers.remove(workName);
    }

    public void doWork(String workName) {
    
    
        ((Worker)workers.get(workName)).doWork(workName);
    }
}

    在项目经理类中定义了一个储存被委派者(各个部门员工)的Map集合,在add方法中,将传来的workName参数和Worker对象以键值对的形式储存在map集合里,在doWork方法中根据传进来的workName参数来动态的调用不同部门成员的doWork方法,来实现将任务分解并交由相应的被委派者去执行。
    4. 辅助代码
    客户端测试类Client(公司总经理角色)

public class Client {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("公司总经理将房地产项目交给项目经理张三来完成");
        XiangMuJingLi xiangMuJingLi = new XiangMuJingLi("张三");
        xiangMuJingLi.add("土建施工",new GongChengBu("李四"));
        xiangMuJingLi.add("验工计价",new GongChengBu("王五"));
        xiangMuJingLi.add("物资设备调度",new GongChengBu("赵六"));
        System.out.println("项目经理张三完成工作分配");
        System.out.println("=======================");
        xiangMuJingLi.doWork("土建施工");
        xiangMuJingLi.doWork("验工计价");
        xiangMuJingLi.doWork("物资设备调度");
    }
}

    公司总经理将房地产项目交给了项目经理张三来完成,张三调用自己的doWork方法,并在参数中给出了需要具体完成的工作。表面上来看,确实是项目经理张三去完成这些土建施工、验工计价、物资设备调度的工作,其实是项目经理张三分别调用不同部门员工的doWork方法,来共同完成这个房地产项目。项目经理仅仅需要做的就是权衡、分配不同任务的工作给对应的部门员工。
    5. 结果及分析
    编译并运行程序,输出结果如下:

公司总经理将房地产项目交给项目经理张三来完成
项目经理张三完成工作分配
=======================
工程部:李四完成土建施工工作
工程部:王五完成验工计价工作
工程部:赵六完成物资设备调度工作

    在这个房地产建设项目中,项目经理的角色仅仅是做了任务分配的工作,在使用委派模式时,还可以在项目经理的doWork方法中实现更加详细的其他操作,来实现任务工作的权衡和委派,以达到更好的处理具体任务。
4 委派模式效果与应用
    4.1 模式优缺点
    1. 委派模式的优点
    (1)委派模式通过委派者,将具体任务的实现隐藏,外部调用者不用关心其内部的具体实现,提供外部调用的统一处理接口,易于扩展,简化调用。
    (2)通过任务委派能够将一个大型的任务细化,然后通过统一管理这些子"任务的完成情况实现任务的跟进,能够加快任务执行的效率。
    2. 委派模式的缺点
    (1)委派者模式的使用将会使用更多的类,代码量会变大。对于理解委派者内部的业务逻辑造成学习的困难,
    (2)任务委派方式需要根据任务的复杂程度进行不同的改变,在任务比较复杂的情况下可能需要进行多重委派,容易造成紊乱。
    4.2 模式适用环境
    在以下情况下可以使用委派模式:
    (1)在设计系统时,需要用一个对象统一处理请求,并需要将请求分发到具体的请求处理类上。
    (2)让客户端能够忽略不同对象具体任务的执行逻辑,客户端可以针对委派者进行编程,无需关心具体任务的实现细节。
    (3)需要根据不同的使用环境,对具体任务进行不同方式的处理,根据传入的环境参数,动态的选择具体的操作逻辑。
    4.3 模式应用
    springMVC中大量使用了委派模式,例如DispatcherServlet就是很经典的委派模式的应用。
    客户端的请求就相当于实例中的公司总经理角色,DispatcherServlet就是其中的委派者,也就是项目经理的角色,处理细部工作的其他解析器就是被委派者,也就是部门员工的角色。
    DispatcherServlet的业务流程如图4所示:
在这里插入图片描述

图4 DispatcherServlet业务流程图

    DispatcherServlet的大致委派流程:
    (1)客户端发起请求,会请求到DispatcherServlet中,DispatcherServlet会对请求额URL进行解析,获得请求资源标识符(URI)。
    (2)DispatcherServlet会根据得到的URI,调用HandlerMapping映射处理器,获得该Handler配置的所有相关对象,一个Handler处理器和多个HandlerInterceptor拦截处理器对象,HandleMapping映射处理器将会把请求映射为HandlerExecutionChain对象返回。
    (3)DispatcherServlet会根据获得的Handler处理器选择成合适的HandlerAdapter处理器适配器,这是适配器设计模式的应用,来很轻易的支持更多类型的Handler处理器。HandlerAdapter处理器适配器提取Request中的模型参数,将其填充到Handler中并执行Handler处理器。
    (4)Handler执行完成后会向DispatcherServlet返回一个ModleAndView对象,DispatcherServlet再调用ViewResolver视图解析器将其解析为View对象,ViewResolver视图解析器向DispatcherServlet返回得到的View对象。
    (5)最后DispatcherServlet将Model参数传入给View对象,结合Model和View,来渲染视图,最后将渲染结果返回给客户端。

猜你喜欢

转载自blog.csdn.net/qq_37428140/article/details/122560129