大话设计模式笔记(八)の模板方法模式
举个栗子
问题描述
小时候数学老师的随堂测验,都是在黑板上抄题目,然后再作答案。写一个抄题目的程序。
简单实现
学生甲抄的试卷
1. /**
2. * 学生甲抄的试卷
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperA {
6.
7. // 试题1
8. public void testQuestion1(){
9. System.out.println("路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年");
10. System.out.println("答案:b");
11. }
12.
13. // 试题2
14. public void testQuestion2(){
15. System.out.println("鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代");
16. System.out.println("答案:b");
17. }
18.
19. }
20.
学生乙抄的试卷
1. /**
2. * 学生乙抄的试卷
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperB {
6.
7. // 试题1
8. public void testQuestion1(){
9. System.out.println("路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年");
10. System.out.println("答案:a");
11. }
12.
13. // 试题2
14. public void testQuestion2(){
15. System.out.println("鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代");
16. System.out.println("答案:a");
17. }
18.
19. }
20.
测试
1. public class Test {
2.
3. public static void main(String[] args) {
4. System.out.println("学生甲抄的试卷:");
5. TestPaperA studentA = new TestPaperA();
6. studentA.testQuestion1();
7. studentA.testQuestion2();
8.
9. System.out.println("学生乙抄的试卷:");
10. TestPaperB studentB = new TestPaperB();
11. studentB.testQuestion1();
12. studentB.testQuestion2();
13. }
14.
15. }
16.
测试结果
1. 学生甲抄的试卷:
2. 路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年
3. 答案:b
4. 鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代
5. 答案:b
6. 学生乙抄的试卷:
7. 路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年
8. 答案:a
9. 鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代
10. 答案:a
11.
存在问题
两个学生抄试卷都非常类似,除了答案不同,没什么不一样,这样又容易错,又难以维护。因此老师出一份试卷,打印多份,让学生填写答案就可以了。应该把试题和答案分离,抽出一个父类,让两个子类继承它,公共的试题代码写到父类当中就行了。
提炼代码
试题父类
1. /**
2. * 试题父类-动漫考题
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaper {
6.
7. // 试题1
8. public void testQuestion1(){
9. System.out.println("路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年");
10. }
11.
12. // 试题2
13. public void testQuestion2(){
14. System.out.println("鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代");
15. }
16.
17. }
18.
学生甲抄的试卷-版本2
1. /**
2. * 学生甲抄的试卷-版本2
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperA2 extends TestPaper{
6.
7. @Override
8. public void testQuestion1() {
9. super.testQuestion1();
10. System.out.println("答案:b");
11. }
12.
13. @Override
14. public void testQuestion2() {
15. super.testQuestion2();
16. System.out.println("答案:b");
17. }
18. }
19.
学生乙抄的试卷-版本2
1. /**
2. * 学生乙抄的试卷-版本2
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperB2 extends TestPaper{
6.
7. @Override
8. public void testQuestion1(){
9. super.testQuestion1();
10. System.out.println("答案:a");
11. }
12.
13. @Override
14. public void testQuestion2(){
15. super.testQuestion2();
16. System.out.println("答案:a");
17. }
18.
19. }
20.
客户端测试代码与测试结果此处省略,同上述简单实现。
存在的问题
- 既然用了继承,并且肯定这个继承有意义,就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复
- 当我们要完成在某一个细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理
- 在上面提炼的代码中,每个学生只是输出的答案不同,其他全部都是一样的,应该在此处改成一个虚方法,让每个子类去重写即可
模板方法模式
定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。
UML图
代码实现
模板方法父类-动漫考题
1. /**
2. * 模板方法父类-动漫考题
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public abstract class TestPaper {
6.
7. // 试题1
8. public void testQuestion1(){
9. System.out.println("路飞在顶上战争之后,修炼了多久? a.3天 b.2年 c.2天 d.3年");
10. System.out.println("答案:" + answer1());//改成一个虚方法,下同
11. }
12.
13. // 试题2
14. public void testQuestion2(){
15. System.out.println("鸣人是第几代火影? a.六代 b.七代 c.八代 d.九代");
16. System.out.println("答案:" + answer2());
17. }
18.
19. // 此方法的目的就是给继承的子类重写,因为这里每个人的答案都是不同的
20. public abstract String answer1();
21. public abstract String answer2();
22.
23. }
24.
学生甲抄的试卷-模板方法实现
1. /**
2. * 学生甲抄的试卷-模板方法实现
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperA3 extends TestPaper{
6.
7. @Override
8. public String answer1() {
9. return "b";
10. }
11.
12. @Override
13. public String answer2() {
14. return "b";
15. }
16.
17. }
18.
学生乙抄的试卷-模板方法实现
1. /**
2. * 学生乙抄的试卷-模板方法实现
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class TestPaperB3 extends TestPaper{
6.
7. @Override
8. public String answer1() {
9. return "a";
10. }
11.
12. @Override
13. public String answer2() {
14. return "a";
15. }
16.
17. }
18.
模板方法测试
1. /**
2. * 模板方法测试
3. * Created by callmeDevil on 2019/7/14.
4. */
5. public class Test3 {
6.
7. public static void main(String[] args) {
8. System.out.println("学生甲抄的试卷:");
9. // 将子类变量的声明改成父类,利用多态性实现了代码的复用
10. TestPaper studentA = new TestPaperA3();
11. studentA.testQuestion1();
12. studentA.testQuestion2();
13.
14. System.out.println("学生乙抄的试卷:");
15. TestPaper studentB = new TestPaperB3();
16. studentB.testQuestion1();
17. studentB.testQuestion2();
18. }
19.
20. }
21.
测试结果是一致的,此处不再贴出。
总结
- 模板方法模式是通过把不变的行为搬移到父类,去除子类中重复的代码来体现它的优势
- 模板方法模式就是提供了一个很好的代码复用平台
- 当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
Pass:以上纯属个人理解~~如果发现有错或是心存建议意见等,欢迎大家评论或联系~(# ゚Д゚)~祝大家身体健康学习进步工作顺利生活愉快!
版权归 callmeDevil 所有,如需转载请标注转载来源
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥