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