目录
- 背景:
- 模板方法定义:
- 步骤:
- 初始版: 每个人都抄卷子,然后抄完写自己的答案
- 第一版:将试卷的题抽象出来
- 第二版:将每个人回答的部分抽象出来
- 第三版:将答题步骤封装出来(这里书上写的比较灵活)
- 版本4:基于大话设计模式上版本三展开想象回归业务,这里的所谓步骤仅仅是答题顺序吗,是不是还有别的可能(如A要先吃饭再睡觉,B要先做第一题再做第二题)
- 版本5:基于书上的代码是不是可以推断出来只要是至少包含两个方法的代码,都可以使用模板方法(方法个数)
- 分析
- 自动化代码:
- 未来展望:
- 总结:
背景:
为什么要学习设计模式?
面向对象设计思想分为几层:
Spring相关代码
设计模式
软件七大设计原则
复用扩充维护
封装继承多态
抽象
这样就可以看出来,设计模式处在承上启下的重要位置,只有把设计模式学好,我们才能更加深刻理解Spring。
模板方法定义:
定义一个操作中的算法骨架,而将一些步骤延迟到子类中,模板方法是的子类可以不改变一个算法的结构即可重定义改算法的某些特定步骤。
步骤:
业务场景:两个人做一套卷子,两个人有自己的答案。
初始版: 每个人都抄卷子,然后抄完写自己的答案
package com.example.Template.v1;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 10:26
* @Version: 1.0
*/
public class Client {
public static void main(String[] args) {
TestPaperA studentA = new TestPaperA();
studentA.testQueation1();
studentA.testQueation2();
studentA.testQueation3();
TestPaperB studentB = new TestPaperB();
studentB.testQueation1();
studentB.testQueation2();
studentB.testQueation3();
}
}
package com.example.Template.v1;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 09:27
* @Version: 1.0
*/
public class TestPaperA {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子");
System.out.println("答案:B");
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语");
System.out.println("答案:B");
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色");
System.out.println("答案:B");
}
}
package com.example.Template.v1;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 09:27
* @Version: 1.0
*/
public class TestPaperB {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子");
System.out.println("答案:A");
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语");
System.out.println("答案:A");
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色");
System.out.println("答案:A");
}
}
package com.example.Template.v1;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 09:27
* @Version: 1.0
*/
public class TestPaperB {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子");
System.out.println("答案:A");
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语");
System.out.println("答案:A");
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色");
System.out.println("答案:A");
}
}
第一版:将试卷的题抽象出来
public class Client {
public static void main(String[] args) {
TestPaperA studentA = new TestPaperA();
studentA.testQueation1();
studentA.testQueation2();
studentA.testQueation3();
TestPaperB studentB = new TestPaperB();
studentB.testQueation1();
studentB.testQueation2();
studentB.testQueation3();
}
}
package com.example.Template.v2;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v2
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 10:32
* @Version: 1.0
*/
public class TestPaper {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子");
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语");
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色");
}
}
package com.example.Template.v2;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 09:27
* @Version: 1.0
*/
public class TestPaperA extends TestPaper{
public void testQueation1(){
super.testQueation1();
System.out.println("答案:B");
}
public void testQueation2(){
super.testQueation2();
System.out.println("答案:B");
}
public void testQueation3(){
super.testQueation3();
System.out.println("答案:B");
}
}
package com.example.Template.v2;
/**
* @BelongsProject: JAVAtest
* @BelongsPackage: com.example.Template.v1
* @Author: GuoYuan.Zhao
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-09-14 09:27
* @Version: 1.0
*/
public class TestPaperB {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子");
System.out.println("答案:A");
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语");
System.out.println("答案:A");
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色");
System.out.println("答案:A");
}
}
第二版:将每个人回答的部分抽象出来
public class Client {
public static void main(String[] args) {
TestPaperA studentA = new TestPaperA();
studentA.testQueation1();
studentA.testQueation2();
studentA.testQueation3();
TestPaperB studentB = new TestPaperB();
studentB.testQueation1();
studentB.testQueation2();
studentB.testQueation3();
}
public class TestPaper {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子"+"答案"+ getAnswer1());
}
public String getAnswer1(){
return "A";
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语"+getAnswer2());
}
public String getAnswer2(){
return "A";
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色"+getAnswer3());
}
public String getAnswer3(){
return "A";
}
}
public class TestPaperA extends TestPaper {
public String getAnswer1(){
System.out.println("A");
return "A";
}
public String getAnswer2(){
System.out.println("A");
return "A";
}
public String getAnswer3(){
System.out.println("A");
return "A";
}
}
public class TestPaperB extends TestPaper {
public String getAnswer1(){
System.out.println("B");
return "B";
}
public String getAnswer2(){
System.out.println("B");
return "B";
}
public String getAnswer3(){
System.out.println("B");
return "B";
}
}
第三版:将答题步骤封装出来(这里书上写的比较灵活)
public class Client {
public static void main(String[] args) {
TestPaperA studentA = new TestPaperA();
studentA.templateMethod();
TestPaperB studentB = new TestPaperB();
studentB.templateMethod();
}
}
public class TestPaper {
public void testQueation1(){
System.out.println("你喜欢吃啥东西呢? A:苹果 B:香蕉 c:橙子"+"答案"+ getAnswer1());
}
public String getAnswer1(){
return "A";
}
public void testQueation2(){
System.out.println("你喜欢的学科是啥呢? A:语文 B:数学 c:英语"+getAnswer2());
}
public String getAnswer2(){
return "A";
}
public void testQueation3(){
System.out.println("你喜欢的颜色是啥呢? A:红色 B:绿色 c:蓝色"+getAnswer3());
}
public String getAnswer3(){
return "A";
}
public void templateMethod(){
this.testQueation1();
this.testQueation2();
this.testQueation3();
}
}
public class TestPaperA extends TestPaper {
public String getAnswer1(){
System.out.println("A");
return "A";
}
public String getAnswer2(){
System.out.println("A");
return "A";
}
public String getAnswer3(){
System.out.println("A");
return "A";
}
}
public class TestPaperB extends TestPaper {
public String getAnswer1(){
System.out.println("B");
return "B";
}
public String getAnswer2(){
System.out.println("B");
return "B";
}
public String getAnswer3(){
System.out.println("B");
return "B";
}
}
版本4:基于大话设计模式上版本三展开想象回归业务,这里的所谓步骤仅仅是答题顺序吗,是不是还有别的可能(如A要先吃饭再睡觉,B要先做第一题再做第二题)
版本5:基于书上的代码是不是可以推断出来只要是至少包含两个方法的代码,都可以使用模板方法(方法个数)
分析
package com;
abstract class AbstractClass {
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void templateMethod(){
PrimitiveOperation1();
PrimitiveOperation2();
System.out.println( );
}
}
****************
package com;
public class ConcreteClassA extends AbstractClass{
public void PrimitiveOperation1() {
// TODO Auto-generated method stub
System.out.println("A的具体方法1");
}
public void PrimitiveOperation2() {
// TODO Auto-generated method stub
System.out.println("A的具体方法2");
}
}
*******************
package com;
public class ConcreteClassB extends AbstractClass{
public void PrimitiveOperation1() {
// TODO Auto-generated method stub
System.out.println("B的具体方法1");
}
public void PrimitiveOperation2() {
// TODO Auto-generated method stub
System.out.println("B的具体方法2");
}
}
****************
package com;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractClass c;
c=new ConcreteClassA();
c.templateMethod();
c=new ConcreteClassB();
c.templateMethod();
}
}
看上边的代码是不是可以激发你的想象力吗?
模板方法中的templateMethod 方法中打印最后一行空格给大家留下了想象的空间,是第三个题目还是为了让输入结果错开,看着分界线明显呢。
概念里边说的骨架,
1、并不仅仅是templateMethod 中定义了执行方法的顺序
2、还有这几个方法本身就是骨架,子类大概率会重写抽象类中的抽象方法(方法名一样,返回类型一样,这不算是骨架吗)
体现了依赖倒置:
templateMethod 中调用了PrimitiveOperation2和PrimitiveOperation1,但是
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
这俩方法在父类中根本没有具体实现,只有真正到子类的时候,去执行子类中的具体方法,
倒置是什么意思?
细节依赖于抽象:子类方法起名要按照父类起,且在客户端子类对象.templateMethod (),运行起来要按照父类templateMethod 方法的代码步骤执行。
是抽象不依赖于细节:抽象类中的方法名和templateMethod 中的方法先后顺序不会因为子类发生变化而改变。
自动化代码:
子类可以抽出模板:
public class ConcreteClassX extends AbstractClass{
public void PrimitiveOperation1() {
//通过前端传过来
}
public void PrimitiveOperation2() {
//通过前端传过来
}
}
可以看到客户端也有重复性代码:
AbstractClass c;
c=new ConcreteClassA();
c.templateMethod();
c=new ConcreteClassB();
c.templateMethod();
也可以通过模板实现
未来展望:
客户端部分可以拆成和策略模式一样,任意组合创建不同的子类对象。
再进一步灵活加上工厂方法,就可以自动配置组合方式。(客户端传参)
总结:
从版本1开始,我们一步步增加灵活性,多维度思考,主要围绕复用扩充维护三方面考虑,代码越来越灵活。