设计模式09-委派模式与模板方法模式详解

1.9.设计模式-委派模式与模板方法模式详解

1.9.1.委派模式详解

时长:40min

目标:

  掌握委派模式的写法,精简代码逻辑,提升程序可读性

  学会用模板方法模式,梳理使用工作中流程标准化的业务场景。

9.1.1.委派模式定义

   Delegate Pattern,又叫委托模式。它的基本作用就是负责任务的调度和任务分配,将任务的分配和执行分离开来。

 可以看成是一种特殊情况下的静态代理的全权代理。

  不属于GOF 23种设计模式之一。

  属于行为型模式。

9.1.1.1.使用场景

  1.委派对象本身不知道如何处理一个任务(或请求),把请求交给其他对象来处理

  2.实现程序的解耦

9.1.1.2.委派模式在生活中应用

  1.老板给员工下达任务,安排工作

  2.授权委托书

9.1.2.委派模式的写法

9.1.2.1.通用写法

 1.系统类图设计
9.1.2.2.具体场景应用

  在老板,和员工的关系中,老板一般是向各部门主管下达任务,再由主管向下面的员工安排工作。

1.代码实现

【1】顶层员工接口定义

package com.wf.delegate.general;

/**
 * @ClassName IEmployee
 * @Description 员工顶层接口
 * @Author wf
 * @Date 2020/6/11 9:53
 * @Version 1.0
 */
public interface IEmployee {
    void doWork(String task);
}

【2】部门主管类

  主管,也是属于老板的员工,需要实现接口。【根据员工的特长,分配员工任务】

package com.wf.delegate.demo.simple;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName Leader
 * @Description 部门主管
 * @Author wf
 * @Date 2020/6/11 9:59
 * @Version 1.0
 */
public class Leader implements IEmployee {
    private Map<String,IEmployee> employeeMap = new HashMap<String,IEmployee>();

    public Leader() {
        employeeMap.put("爬虫",new EmployeeA());
        employeeMap.put("海报图",new EmployeeB());
    }

    @Override
    public void doWork(String task) {
        //结合策略模式
        if(!employeeMap.containsKey(task)){
            //卖一个产品
            System.out.println("这个任务【"+task+"】,超出我的能力范围");
            return;
        }
        employeeMap.get(task).doWork(task);
    }
}

【3】主管下,两个员工

package com.wf.delegate.demo.simple;

/**
 * @ClassName EmployeeB
 * @Description 部门主管,下员工B
 * @Author wf
 * @Date 2020/6/11 9:59
 * @Version 1.0
 */
public class EmployeeB implements IEmployee {
    private String goodAt = "平面设计";
    @Override
    public void doWork(String task) {
        System.out.println("我是员工B,我擅长【"+goodAt+"】,现在开始做【"+task+"]工作");
    }
}
package com.wf.delegate.demo.simple;

/**
 * @ClassName EmployeeA
 * @Description 部门主管下,员工A
 * @Author wf
 * @Date 2020/6/11 9:59
 * @Version 1.0
 */
public class EmployeeA implements IEmployee {
    private String goodAt = "编程";
    @Override
    public void doWork(String task) {
        System.out.println("我是员工A,我擅长【"+goodAt+"】,现在开始做【"+task+"]工作");
    }
}

【4】老板

package com.wf.delegate.demo.simple;

/**
 * @ClassName Boss
 * @Description 老板
 * @Author wf
 * @Date 2020/6/12 10:34
 * @Version 1.0
 */
public class Boss {
    /**
     * 直接给主管分配任务
     * @param task
     * @param leader
     */
    public void command(String task, Leader leader){
        leader.doWork(task);
    }
}

【5】测试类

package com.wf.delegate.demo.simple;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author wf
 * @Date 2020/6/12 10:44
 * @Version 1.0
 */
public class Test {
    public static void main(String[] args) {
        new Boss().command("海报图",new Leader());
        new Boss().command("爬虫",new Leader());
        new Boss().command("卖手机",new Leader());
    }
}

测试结果如下:

 【6】 系统类图

 9.1.3.委派模式在源码中应用

9.1.3.1.jdk中ClassLoader

 ClassLoader的双亲委派机制,就是委派模式的应用。

9.1.3.2.jdk中Method类的invoke方法

 这里直接全权委托,MethodAccessor来代理。并返回它的处理结果。

9.1.3.3.spring中BeanDefinitionParserDelegate委派器

9.1.4.委派模式的总结

9.1.4.1.优缺点总结

优点:

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

加快任务执行的效率

缺点:

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

9.1.4.2.委派模式与其它设计模式的关系

委派模式与代理模式:

委派:

  行为模式

  注重任务分派,注重结果。

  是一种特殊的静态代理,相当于全权代理。

代理:

  结构型模式

  注重代码功能增强,注重过程。

1.9.2.模板方法模式详解

时长:50min

9.2.1.委派模式定义

定义

  Template Method Pattern,通常又叫模板模式。是指定义一个算法的骨架,并允许子类为其中

的一个或多个步骤提供实现。

  模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

  属于行为型模式。

9.2.1.1.适用场景

  1.一次性实现一个算法不变的部分,并将可变的行为留给子类实现。

  2.各子类中公共行为提取出来,放到公共的父类中,去除代码重复

9.2.1.2.生活中模板方法的应用

  1.流程性事务,如:煮饭,简历制作

9.2.2.模板方法的通用实现

9.2.2.1.类图设计

 说明:

  模板方法适用于抽取公共逻辑去除重复代码。顶层抽象类设计好公共的代码逻辑,或控制流程

  不同的实现部分,通过实现不同的子类,达到差异化处理。

  需要子类差异化实现的方法,通常声明为protected。

9.2.2.2.代码实现
1.顶层抽象类
package com.wf.template.general;

/**
 * @ClassName AbstractClass
 * @Description 顶层抽象类,定义模块方法
 * @Author wf
 * @Date 2020/6/12 14:47
 * @Version 1.0
 */
public abstract class AbstractClass {
    protected void step1(){
        System.out.println("AbstractClass:step1()");
    }
    protected void step2(){
        System.out.println("AbstractClass:step2()");
    }
    protected void step3(){
        System.out.println("AbstractClass:step3()");
    }
    //声明为final,避免子类重写
    public final void templateMethod(){
        this.step1();
        this.step2();
        this.step3();
    }
    
}
2.子类实现
package com.wf.template.general;

/**
 * @ClassName ConcreteClassA
 * @Description 具体实现子类A
 * @Author wf
 * @Date 2020/6/12 14:49
 * @Version 1.0
 */
public class ConcreteClassA extends AbstractClass {
    @Override
    protected void step1() {
        System.out.println("ConcreteClassA:step1()");
    }
}
package com.wf.template.general;

/**
 * @ClassName ConcreteClassB
 * @Description 具体实现子类B
 * @Author wf
 * @Date 2020/6/12 14:49
 * @Version 1.0
 */
public class ConcreteClassB extends AbstractClass {
    @Override
    protected void step2() {
        System.out.println("ConcreteClassB:step2()");
    }
}
3.测试类
package com.wf.template.general;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author wf
 * @Date 2020/6/12 14:50
 * @Version 1.0
 */
public class Test {
    public static void main(String[] args) {
        AbstractClass abc = new ConcreteClassA();
        abc.templateMethod();
        System.out.println("---------------------------------------");
        abc = new ConcreteClassB();
        abc.templateMethod();
    }
}

测试结果如下:

 9.2.4.模板方法的实际应用示例

9.2.4.1.以课程为例
1.定义抽象模板类
package com.wf.template.demo.course;

/**
 * @ClassName AbstractCourse
 * @Description 抽象模板类
 * @Author wf
 * @Date 2020/6/12 15:12
 * @Version 1.0
 */
public abstract class AbstractCourse {
    public final void createCourse(){
        //1.发布预习资料
        postPreResource();
        //2.制作课件ppt
        createPPT();
        //3.直播授课
        liveVideo();
        //4.上传课堂笔记
        postResource();
        //5.提交作业
        postHomework();

        //6.是否要批改作业
        if(needCheckHomeWork()){
            checkHomeWork();
        }
    }

    public abstract void checkHomeWork();//不同事务,定义为抽象方法
    //钩子方法,由子类重写
    protected boolean needCheckHomeWork(){
        return false;
    }

    protected void postHomework() {
        System.out.println("提交作业");
    }

    protected void postResource() {
        System.out.println("上传课堂笔记");
    }

    protected void liveVideo() {
        System.out.println("直播授课");
    }

    protected void createPPT() {
        System.out.println("制作课件ppt");
    }

    protected void postPreResource() {
        System.out.println("发布预习资料");
    }
}
2.课程子类实现
package com.wf.template.demo.course;

/**
 * @ClassName JavaCourse
 * @Description java课程
 * @Author wf
 * @Date 2020/6/12 15:21
 * @Version 1.0
 */
public class JavaCourse extends AbstractCourse {
    private boolean needCheckHomeWork = false;

    public void setNeedCheckHomeWork(boolean needCheckHomeWork) {
        this.needCheckHomeWork = needCheckHomeWork;
    }

    @Override
    public void checkHomeWork() {
        System.out.println("检查Java作业");
    }

    @Override
    protected boolean needCheckHomeWork() {
        return this.needCheckHomeWork;
    }
}
package com.wf.template.demo.course;

/**
 * @ClassName PythonCourse
 * @Description Python课程
 * @Author wf
 * @Date 2020/6/12 15:22
 * @Version 1.0
 */
public class PythonCourse extends AbstractCourse {
    @Override
    public void checkHomeWork() {
        System.out.println("检查Python作业");
    }
}
3.测试类
package com.wf.template.demo.course;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author wf
 * @Date 2020/6/12 15:22
 * @Version 1.0
 */
public class Test {
    public static void main(String[] args) {
        System.out.println("=============架构师课程===============");
        JavaCourse java = new JavaCourse();
        //由客户端决定,是否需要检查作业
        java.setNeedCheckHomeWork(true);
        java.createCourse();

        System.out.println("=============Python课程===============");

        PythonCourse python = new PythonCourse();
        python.createCourse();
    }
}

 测试结果如下:

 9.2.4.2.实际业务中模板方法的应用

  在jdbc操作时,spring中定义JdbcTemplate模板类。

1.抽象模板类
package com.wf.template.demo.jdbc;

import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName JdbcTemplate
 * @Description jdbc模板类
 * @Author wf
 * @Date 2020/6/12 15:45
 * @Version 1.0
 */
@Slf4j
public abstract class JdbcTemplate {
    private DataSource dataSource;

    public JdbcTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    public final List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values){
        //1.获取连接
        try {
            Connection conn = getConnection();
            //2.创建语句集
            PreparedStatement ps = this.createPrepareStatement(conn,sql);
            //3.执行语句集
            ResultSet rs = this.executeQuery(ps, values);
            //4.封装结果
            List<?> result = this.parseResultSet(rs,rowMapper);
            //5.关闭结果集
            rs.close();
            //6.关闭语句集
            ps.close();
            //7.关闭连接
            conn.close();
            return result;
        } catch (SQLException e) {
            log.error("获取Connection连接异常:{}",e.getCause().getMessage());
        }
        return null;
    }

    private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws SQLException {
        List<Object> result = new ArrayList<>();
        int rowNum = 1;
        while (rs.next()){
            result.add(rowMapper.mapRow(rs,rowNum++));
        }
        return result;
    }

    private ResultSet executeQuery(PreparedStatement ps, Object[] values) throws SQLException {
        for(int i=0; i<values.length; i++){
            ps.setObject(i,values[i]);
        }
        return ps.executeQuery();
   }

    private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }


    private Connection getConnection() throws SQLException {
        return  this.dataSource.getConnection();
    }
}

结果集映射接口:

package com.wf.template.demo.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @ClassName RowMapper
 * @Description 结果集映射
 * @Author wf
 * @Date 2020/6/12 15:47
 * @Version 1.0
 */
public interface RowMapper<T> {
    //
    T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
2.dao实现类
package com.wf.template.demo.jdbc.dao;

import com.wf.template.demo.jdbc.JdbcTemplate;
import com.wf.template.demo.jdbc.pojo.Member;

import javax.sql.DataSource;
import java.util.List;

/**
 * @ClassName MemberDao
 * @Description dao实现
 * @Author wf
 * @Date 2020/6/12 16:06
 * @Version 1.0
 */
public class MemberDao extends JdbcTemplate {
    public MemberDao(DataSource dataSource) {
        super(dataSource);
    }

    public List<?> findAll(){
        String sql = "select * from t_member";
        return super.executeQuery(sql,(rs,rowNum)->{
            Member member = new Member();
            //如果字段过多,使用原型模式
            member.setUsername(rs.getString("username"));
            member.setPassword(rs.getString("password"));
            member.setAddr(rs.getString("addr"));
            member.setAge(rs.getInt("age"));
            return member;
        },null);
    }
}
3.实体类
package com.wf.template.demo.jdbc.pojo;

/**
 * @ClassName Member
 * @Description 员工类
 * @Author wf
 * @Date 2020/6/12 16:11
 * @Version 1.0
 */
public class Member {
    private String username;
    private String password;
    private Integer age;
    private String addr;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}
4.测试类
package com.wf.template.demo.jdbc;

import com.wf.template.demo.jdbc.dao.MemberDao;

import java.util.List;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author wf
 * @Date 2020/6/12 16:16
 * @Version 1.0
 */
public class Test {
    public static void main(String[] args) {
        MemberDao dao = new MemberDao(null);
        List<?> result = dao.findAll();

    }
}

说明:

  这里未经过测试,需要导入相关包,配置数据源,数据库连接配置,数据表创建。

9.2.5.模板方法模式在源码中应用

9.2.5.1.spring的jdbcTemplate模板
9.2.5.2.jdk中AbstractList

9.2.5.3.servlet中HttpServlet
9.2.5.4.mybatis中BaseExecutor

 9.2.6.模板模式的总结

9.2.6.1.优缺点总结

优点:

  1.利用它,可以将相同的处理逻辑抽取到抽象父类中,提高代码复用性

  2.将不同代码,放在不同子类中来实现 ,通过对子类的扩展增加新的行为,提高代码扩展性

  3.把不变的逻辑抽取到公共父类中,去除子类的重复代码,符合开闭原则

缺点:

  1.类数量增加,每一个抽象类需要一个实现子类

  2.增加系统复杂性

  3.继承关系自身的缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

原文地址:https://www.cnblogs.com/wfdespace/p/13091408.html