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章 怎么出试卷?——模版方法模式的更多相关文章

  1. [Python设计模式] 第12章 基金理财更省事——外观模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟股民直接炒股的代码,比如股民投资了股票1,股票2,股票3,国债 ...

  2. [Python设计模式] 第22章 手机型号&软件版本——桥接模式

    github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...

  3. [Python设计模式] 第2章 商场收银软件——策略模式

    github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...

  4. [Python设计模式] 第25章 联合国维护世界和平——中介者模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目背景 联合国在世界上就是中介者的角色,各国之间的关系复杂,类似不同的对象和对 ...

  5. [Python设计模式] 第23章 烤串的哲学——命令模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟,顾客直接向烤串师傅提需求. class Barbecuer( ...

  6. JS常用的设计模式(10)——模版方法模式

    模式方法是预先定义一组算法,先把算法的不变部分抽象到父类,再将另外一些可变的步骤延迟到子类去实现.听起来有点像工厂模式( 非前面说过的简单工厂模式 ). 最大的区别是,工厂模式的意图是根据子类的实现最 ...

  7. Python设计模式——模版方法模式

    1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...

  8. 【java设计模式】(10)---模版方法模式(案例解析)

    一.概念 1.概念 模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式. 它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的 ...

  9. 第13章 模版方法模式(Template Method)

    原文  第13章 模版方法模式(Template Method) 模板模式 模板模式 举例:模拟下数据库的update方法,先删除在插入. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

随机推荐

  1. Fiddler抓包10-会话框添加查看get与post请求类型

    前言 在使用fiddler抓包的时候,查看请求类型get和post每次只有点开该请求,在Inspectors才能查看get和post请求,不太方便.于是可以在会话框直接添加请求方式. 一.添加会话框菜 ...

  2. Tesseract环境搭建及编译安装

    Tesseract环境搭建及编译安装 Tesseract源码都是C++源码:对于不咋会C++的人来说,这真是...虽然说语言有相通性,但是...哎!!!!! 分享出来,也希望对大家有所帮助. 环境:w ...

  3. WebApi的调用-2.后台调用

    httpClient调用方式 namespace SOA.Common { //httpClient调用WebApi public class HttpClientHelper { public st ...

  4. android 换行符(\n) 在TextView中显示不正常的问题

    问题描述 在Android开发,使用TextView设置换行的时候,会有这种情况: 1.如果直接在XML文件中写入"aaaaa\nbbbb"可以换行,显示为: aaaaabbbbb ...

  5. Spring3.X jdk8 java.lang.IllegalArgumentException

    异常提示: javax.servlet.ServletException: Servlet.init() for servlet springMVC threw exception org.apach ...

  6. python全栈开发day33-进程间的通信、进程间的数据共享,进程池

    一.昨日内容回顾: 1.  守护进程 1).p.saemon, 2 ).p.terminate 3 ).p.join 2.  同步控制 1).锁,Lock 互斥锁,解决数据安全.进程之间资源抢占问题. ...

  7. Codeforces 1000F One Occurrence 主席树|| 离线+线段树

    One Occurrence 为什么我半年前这么菜呀, 这种场只A三题... 我们在主席树 || 线段树上维护每个数的右边和它一样的数在哪里, 然后就变成了区间求最大值. 注意加进去的时候要把它右边一 ...

  8. CSS3滚动条美化,CSS3滚动条皮肤

    CSS3 -webkit-scrollbar滚动条皮肤美化实现,利用-webkit-scrollbar,-webkit-scrollbar-track,-webkit-scrollbar-thumb这 ...

  9. 6-2 铁轨 uva 514

    较为简单的stack题目 但是还是犯了一些错误: 1. 要想清空栈,直接重新定义较为方便! 2.在if(s.top()==x)时  加上  !s.empty()  否则程序会崩溃 3. 必须要加上i- ...

  10. 笔记:FastAdmin 上传设置

    笔记:FastAdmin 上传设置 FastAdmin 的上传设置为统一配置,在 application/extra/upload.php 中文件中. <?php //上传配置 return [ ...