• 设计模式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.继承关系自身的缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

  • 相关阅读:
    「最小生成树」[HAOI2006]聪明的猴子
    「打表」[Beijing wc2012]算不出的算式
    『看毛片』kmp字符串匹配算法
    「主席树」[Ctsc2018]混合果汁
    Aiiage Camp Day3 B Bipartite
    Aiiage Camp Day2 D domino
    Aiiage Camp Day1 H Littrain wanna be rich
    Aiiage Camp Day1 E Littrain wanna be small
    Aiiage Camp Day1 C Littrain wanna be different
    Aiiage Camp Day1 A Littrain is a loser, in 2018
  • 原文地址:https://www.cnblogs.com/wfdespace/p/13091408.html
Copyright © 2020-2023  润新知