委派模式和模板模式
目录
1、委派模式
1.1 什么是委派模式
委派模式又叫委托模式,委派模式不属于23种设计模式之一,是一种面向对象的设计模式;它的基本任务就是负责任务的分配和任务的调用,是一种特殊的静态代理,也可以理解为全权代理,但是代理模式注重的是过程,而委派模式注重的是结果。
在平常其他设计模式中可能也有体现。同样在现实生活中也有相关的体现,比如一个具体任务的执行,首先是经过高层领导讨论,将具体的任务委派给相关部门经理,部门经理拿到任务通知后去委派相关的员工具体执行任务,委派任务的角色实际并非具体执行任务,而是对任务分发,执行过程进行管理。
1.2 结构图
- 抽象任务角色(Task)这里用IStudent表示:定义一个抽象接口,它有若干个实现类。
- 委派者角色(Delegate)这里用Monitor表示:负责在各个具体角色实例之间做出决策,并判断并调用具体的实现方法。
- 具体任务角色(Concrete)这里用StudentA和StudentB表示:正真执行任务的角色。
1.3 实例演示
实例:生活中,如老师给班长布置任务,班长会把任务委派给各个班委。
public interface IStudent {
void doing(String homework);
}
/**
* @description: 学习委员
* @author: zps
* @create: 2020-05-04 14:25
**/
public class StdudentA implements IStudent{
@Override
public void doing(String homework) {
System.out.println("我是学习委员,我受到来自班长的任务" + homework);
}
}
/**
* @description: 纪律委员
* @author: zps
* @create: 2020-05-04 14:26
**/
public class StudentB implements IStudent{
@Override
public void doing(String homework) {
System.out.println("我是纪律委员,我受到来自班长的任务" + homework);
}
}
/**
* @description: 班长
* @author: zps
* @create: 2020-05-04 14:28
**/
public class Monitor implements IStudent{
private Map<String , IStudent> studentMap = new HashMap<>();
public Monitor(){
studentMap.put("考试" , new StdudentA());
studentMap.put("纪律" , new StudentB());
}
@Override
public void doing(String homework) {
if(!studentMap.containsKey(homework)){
System.out.println("暂时还没有人可以处理该任务,只能班长来干了!");
return;
}
studentMap.get(homework).doing(homework);
}
}
/**
* @description: 老师布置任务
* @author: zps
* @create: 2020-05-04 14:32
**/
public class Teacher {
public static void main(String[] args) {
String task = "纪律";
Monitor monitor = new Monitor();
monitor.doing(task);
}
}
运行结果:
1.4 总结
委派模式在源码中的使用:
- JVM加载类时使用的双亲委派模型:如果一个类加载器 收到了类加载的请求,先把这个请求委派给父类加载器去完成(所以所有的加载请求最终都应该传送到顶层的启动类加载器中),只有当父加载器反馈自己无法完成加载请求时,子加载器才会尝试自己去加载。
ClassLoad中的源码部分:
public abstract class ClassLoader { ... private final ClassLoader parent; ... protected Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException { synchronized(this.getClassLoadingLock(var1)) { Class var4 = this.findLoadedClass(var1); if (var4 == null) { long var5 = System.nanoTime(); try { if (this.parent != null) { //委托给父加载器加载 var4 = this.parent.loadClass(var1, false); } else { var4 = this.findBootstrapClassOrNull(var1); } } catch (ClassNotFoundException var10) { } if (var4 == null) { //如果父加载器不能加载,则自己加载 long var7 = System.nanoTime(); var4 = this.findClass(var1); PerfCounter.getParentDelegationTime().addTime(var7 - var5); PerfCounter.getFindClassTime().addElapsedTimeFrom(var7); PerfCounter.getFindClasses().increment(); } } if (var2) { this.resolveClass(var4); } return var4; } } ....... }
- springmvc中也有用的委派模式。在spring框架中,只要是以Delegate结尾的类机会都用到委派模式
委派模式的优点:
- 务委派能够将一个大型的任务细化,然后通过统一管理这些子任务的完成情况实现任务的跟进,能够加快任务执行的效率。
委派模式的缺点:
- 任务委派方式需要根据任务的复杂程度进行不同的改变,在任务比较复杂的情况下可能需要进行多重委派,容易造成紊乱。
适用场景:
- 2.需要对一个比较复杂的任务进行分解,分发执行并通过一个委派者角色将最终结果返回。
2、模板方法模式
2.1 什么是模板方法模式
模板方法模式又称模板模式,它就是将一系列方法中的固定方法提取到抽象层,完成代码的复用,且通过子类的重写行为改变类的模板方法的功能的改变。它属于行为设计模式。
2.2 结构图
- 模板方法模式共分为两种角色:
- Abstract Class(抽象类):抽象类,提供默认实现的具体方法与供子类实现的抽象方法。
- Concrete Class(具体子类):实现父类声明的抽象方法,重写父类的逻辑。
- 抽象类提供模板方法(包含基本方法的执行顺序,可被重写),里边包含具体方法(子类的通用方法),抽象方法(供子类重写的方法),钩子方法(供子类重写控制模板方法逻辑的方法),子类重写父类,使类具有不同的功能。
2.3 实例
制作一节网课的步骤可以简化为4个步骤:
- 制作PPT
- 录制视频
- 编写笔记
- 提供课程资料
其中1、2、3的动作在所有课程中的固定不变的,步骤3可有可无,步骤4在每个课程都不同(有些课程需要提供源代码,有些需要提供图片文件等)
我们可以在父类中确定整个流程的循序,并实现固定不变的步骤,而把不固定的步骤留给子类实现。甚至可以通过一个钩子方法,让子类来决定流程中某个方法的执行与否
/**
* @description: 网课授课流程模板
* @author: zps
* @create: 2020-05-04 15:11
**/
public abstract class Course {
protected final void makeCourse(){
this.makePPT();
this.makeVideo();
if(isnendNode()){
this.makeNote();
}
this.packageCourse();
}
//固定的步骤使用final修饰
final void makePPT(){
System.out.println("1、制作PPT");
}
final void makeVideo(){
System.out.println("2、制作视频");
}
final void makeNote(){
System.out.println("3、编写笔记");
}
//钩子方法,可以根据业务需求进行设计
protected boolean isnendNode(){
return false;
}
abstract void packageCourse();
}
/**
* @description: javc课程网课
* @author: zps
* @create: 2020-05-04 15:17
**/
public class JavaCourse extends Course{
@Override
protected boolean isnendNode() {
return true;
}
@Override
void packageCourse() {
System.out.println("4、提供Java课程源代码");
}
}
/**
* @description: phyton课程网课
* @author: zps
* @create: 2020-05-04 15:18
**/
public class Phtyon extends Course{
@Override
protected boolean isnendNode() {
return super.isnendNode();
}
@Override
void packageCourse() {
System.out.println("4、提供视频!");
}
}
/**
* @description: 测试
* @author: zps
* @create: 2020-05-04 15:20
**/
public class Test {
public static void main(String[] args) {
System.out.println("Java网课:");
Course java = new JavaCourse();
java.makeCourse();
System.out.println("-----------------");
System.out.println("Phtyon网课:");
Course phtyon = new Phtyon();
phtyon.makeCourse();
}
}
测试结果:
2.4 小节
模板方法模式的主要优点如下:
- 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
- 模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励我们恰当使用继承来实现代码复用。
- 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
- 符合单一职责原则和开闭原则。
模板方法模式的主要缺点如下:
- 会导致类的个数增加,系统更加庞大,设计也更加抽象,此时,可结合桥接模式来进行设计。
适用场景:
- 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。即:一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
源码中的应用:
AbstractList源码中:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { ... public abstract E get(int var1); //该方法将交个子类实现 ... }
- HttpServlet的三个service() , doPost() , doGet() 方法。
- 等等