[Python设计模式] 第10章 怎么出试卷?——模版方法模式
github地址:https://github.com/cheesezh/python_design_patterns
题目
小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题目。设计一个程序,模拟学生A和B抄题目做试卷的过程。
基础版本
class TestPaperA():
def test_question_1(self):
print("题目1: !+1=?,a.2 b.3 c.4. d.1")
print("我选:a")
def test_question_2(self):
print("题目2: 2+1=?,a.2 b.3 c.4. d.1")
print("我选:b")
def test_question_3(self):
print("题目3: 2+2=?,a.2 b.3 c.4. d.1")
print("我选:c")
class TestPaperB():
def test_question_1(self):
print("题目1: !+1=?,a.2 b.3 c.4. d.1")
print("我选:a")
def test_question_2(self):
print("题目2: 2+1=?,a.2 b.3 c.4. d.1")
print("我选:c")
def test_question_3(self):
print("题目3: 2+2=?,a.2 b.3 c.4. d.1")
print("我选:d")
def main():
print("学生A抄的试卷以及答案")
paper_a = TestPaperA()
paper_a.test_question_1()
paper_a.test_question_2()
paper_a.test_question_3()
print("学生B抄的试卷以及答案")
paper_b = TestPaperB()
paper_b.test_question_1()
paper_b.test_question_2()
paper_b.test_question_3()
main()
学生A抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:b
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:c
学生B抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:c
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:d
点评
- 学生A和学生B的考卷题目完全一样,重复代码太多
- 如果老师修改题目,那所有学生都需要改试卷
- 把试卷和答案分离,抽象一个试卷父类,然后学生A和学生B的试卷继承这个父类即可
改进版本1.0——提炼父类
class TestPaper():
def test_question_1(self):
print("题目1: !+1=?,a.2 b.3 c.4. d.1")
def test_question_2(self):
print("题目2: 2+1=?,a.2 b.3 c.4. d.1")
def test_question_3(self):
print("题目3: 2+2=?,a.2 b.3 c.4. d.1")
class TestPaperA(TestPaper):
def test_question_1(self):
super().test_question_1()
print("我选:a")
def test_question_2(self):
super().test_question_2()
print("我选:b")
def test_question_3(self):
super().test_question_3()
print("我选:c")
class TestPaperB(TestPaper):
def test_question_1(self):
super().test_question_1()
print("我选:a")
def test_question_2(self):
super().test_question_2()
print("我选:c")
def test_question_3(self):
super().test_question_3()
print("我选:d")
main()
学生A抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:b
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:c
学生B抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:c
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:d
点评
这还是只初步的泛化,两个类中还有类似的代码。比如都有super().test_question_1(),还有print("我选:a"),除了选项不同,其他都相同。
我们既然用了继承,并且认为这个继承是有意义的,那么父类就应该成为子类的模版,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。
这就需要使用模版方法来处理。
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模版方法来处理。
改进版本2.0——提炼细节
from abc import ABCMeta, abstractmethod
class TestPaper():
__metaclass__ = ABCMeta
def test_question_1(self):
print("题目1: !+1=?,a.2 b.3 c.4. d.1")
print("我选:{}".format(self.answer_1()))
@abstractmethod
def answer_1(self):
pass
def test_question_2(self):
print("题目2: 2+1=?,a.2 b.3 c.4. d.1")
print("我选:{}".format(self.answer_2()))
@abstractmethod
def answer_2(self):
pass
def test_question_3(self):
print("题目3: 2+2=?,a.2 b.3 c.4. d.1")
print("我选:{}".format(self.answer_3()))
@abstractmethod
def answer_3(self):
pass
class TestPaperA(TestPaper):
def answer_1(self):
return "a"
def answer_2(self):
return "b"
def answer_3(self):
return "c"
class TestPaperB(TestPaper):
def answer_1(self):
return "a"
def answer_2(self):
return "c"
def answer_3(self):
return "d"
main()
学生A抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:b
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:c
学生B抄的试卷以及答案
题目1: !+1=?,a.2 b.3 c.4. d.1
我选:a
题目2: 2+1=?,a.2 b.3 c.4. d.1
我选:c
题目3: 2+2=?,a.2 b.3 c.4. d.1
我选:d
点评
此时要有更多的学生来答试卷,只是在试卷的模版上填写选择题的选项答案,即可。
模版方法
模版方法,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤[DP]。
from abc import ABCMeta, abstractmethod
class AbstractClass():
"""
抽象模版类,定义并实现了一个模版方法,这个模版方法一般是一个具体的算法,
它定义了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到
子类实现。当然,顶级逻辑也可能调用一些具体方法。
"""
__metaclass__ = ABCMeta
@abstractmethod
def primitive_operation_1(self):
"""
抽象操作1,放到子类去实现
"""
pass
@abstractmethod
def primitive_operation_2(self):
"""
抽象操作2,放到子类去实现
"""
pass
def template_method(self):
"""
具体模版方法,定义了顶级逻辑骨架
"""
self.primitive_operation_1()
self.primitive_operation_2()
class ConcreteClassA(AbstractClass):
"""
具体类A,给出抽象方法的不同实现
"""
def primitive_operation_1(self):
print("具体类A的操作1")
def primitive_operation_2(self):
print("具体类A的操作2")
class ConcreteClassB(AbstractClass):
"""
具体类B,给出抽象方法的不同实现
"""
def primitive_operation_1(self):
print("具体类B的操作1")
def primitive_operation_2(self):
print("具体类B的操作2")
cls = ConcreteClassA()
cls.template_method()
cls = ConcreteClassB()
cls.template_method()
具体类A的操作1
具体类A的操作2
具体类B的操作1
具体类B的操作2
点评
- 模版方法通过把不变的行为搬移到超类,去除子类中的重复代码来体现它的优势
- 模版方法提供了一个很好的代码复用平台
- 当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模版方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠
[Python设计模式] 第10章 怎么出试卷?——模版方法模式的更多相关文章
- [Python设计模式] 第12章 基金理财更省事——外观模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟股民直接炒股的代码,比如股民投资了股票1,股票2,股票3,国债 ...
- [Python设计模式] 第22章 手机型号&软件版本——桥接模式
github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...
- [Python设计模式] 第2章 商场收银软件——策略模式
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...
- [Python设计模式] 第25章 联合国维护世界和平——中介者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目背景 联合国在世界上就是中介者的角色,各国之间的关系复杂,类似不同的对象和对 ...
- [Python设计模式] 第23章 烤串的哲学——命令模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟,顾客直接向烤串师傅提需求. class Barbecuer( ...
- JS常用的设计模式(10)——模版方法模式
模式方法是预先定义一组算法,先把算法的不变部分抽象到父类,再将另外一些可变的步骤延迟到子类去实现.听起来有点像工厂模式( 非前面说过的简单工厂模式 ). 最大的区别是,工厂模式的意图是根据子类的实现最 ...
- Python设计模式——模版方法模式
1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...
- 【java设计模式】(10)---模版方法模式(案例解析)
一.概念 1.概念 模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式. 它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的 ...
- 第13章 模版方法模式(Template Method)
原文 第13章 模版方法模式(Template Method) 模板模式 模板模式 举例:模拟下数据库的update方法,先删除在插入. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
随机推荐
- 性能测试三:jmeter进阶之图形插件
一.图形化插件的使用 使用Jmeter插件可以更直观的查看tps和响应时间 插件官网: http://jmeter-plugins.org/downloads/all 第一种方法,找到需要的插件下载j ...
- 通过生成支付二维码来实现微信支付的解决方案 - EasyWechat版(转)
上一篇我们讲了在微信浏览器内实现微信支付的功能,它特别适合于一些基于微信公众号的h5站点等,支付流程也相当流畅,但是... 还有一种情况,比如现在北哥兄弟连PC版,是生成了一个二维码,这个二维码是专属 ...
- Android strings.xml中定义字符串显示空格
<string name="str">字 符 串</string> 其中 就表示空格.如果直接在里面键入空格,无论多少空格都只会显示一个. 用的XML转 ...
- 「2017 山东一轮集训 Day7」逆序对
题解: 满满的套路题.. 首先显然从大到小枚举 然后每次生成的逆序对是1----(i-1)的 这样做dp是nk的 复杂度太高了 那我们转化一下问题 变成sigma(ai (ai<i) )= ...
- maven的三种工程pom、jar、war
阅读数:739 maven中的三种工程: 1.pom工程:用在父级工程或聚合工程中.用来做jar包的版本控制. 2.war工程:将会打包成war,发布在服务器上的工程.如网站或服务. 3.jar工程: ...
- Codeforces Round #319 (Div. 2) E - Points on Plane
题目大意:在一个平面里有n个点,点坐标的值在1-1e6之间,让你给出一个遍历所有点的顺序,要求每个点走一次,且 曼哈顿距离之和小于25*1e8. 思路:想了一会就有了思路,我们可以把1e6的x,y坐标 ...
- 【目录】LeetCode Java实现
这里记录一下自己刷的LeetCode题目. 有些博客用英文阐述自己的思路和收获,相当于练习一下英文的表达能力. 比较好的题目有加粗. 1. Two Sum 3. Longest Substring W ...
- 【Java】 剑指offer(2) 不修改数组找出重复的数字
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至少 ...
- 【*】CAS 是什么,Java8是如何优化 CAS 的
文章结构 前言 想要读懂 Java 中的并发包,就是要先读懂 CAS 机制,因为 CAS 是并发包的底层实现原理.本文主要讨论 CAS 是如何保证操作的原子性的 Java8 对 CAS 进行了哪些 ...
- mysql 用户/密码/权限操作
由于最近使用mysql遇到了修改用户密码的问题,所以一块学习了一下关于用户的相关操作: 1. 创建新账户 CREATE USER 'jeffrey'@'localhost'; 2. 账户设置密码 #当 ...