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. jquery----语法扩展(导入js文件)

    简单使用 第一步,新建js文件 第二步,在js文件中添加 $.extend({ "GDP": function () { console.log("哈哈哈哈") ...

  2. python 全栈开发,Day28(复习,os模块,导入模块import和from)

    一.复习 collections 增加了一些扩展数据类型 :namedtuple orderdict defaltdict队列和栈time 时间 三种格式 : 时间戳 结构化 字符串random 随机 ...

  3. Java入门第一章知识点总结

    -d是directory 目录的意思 cls:清楚doc里面的内容 ipconfig:显示网络配置信息 java -version:检查安装的jdk版本信息 是类型自动向上转换.  在输出时,根据当前 ...

  4. 转发(Forward)和重定向(Redirect)的区别

    转发是服务器行为,重定向是客户端行为. 转发(Forword) :通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServle ...

  5. [Reprinted] 使用Spring Data Redis操作Redis(一) 很全面

    Original Address: http://blog.csdn.net/albertfly/article/details/51494080

  6. 6-7 树的层次遍历 uva122

    非常不熟练  照着书大的 晚上尝试一下自己打  了解二叉树  用数组打 第一次: #include<bits/stdc++.h> using namespace std; bool fai ...

  7. 【Java】 剑指offer(54) 二叉搜索树的第k个结点

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给定一棵二叉搜索树,请找出其中的第k小的结点. 思路 设置全局变量 ...

  8. maven在windows下的安装

    1.下载 2.解压 3.修改配置环境 4.验证 5.使用mvn help:system就可以看到下载到本地仓库的文件 6.全局settings 7.建议在m2下拷贝一份属于个人的配置settings

  9. Spring日记_01 之基于maven的Spring环境搭建

    阿里云镜像:maven.aliyun.com 添加Spring坐标: Spring 是java组件容器,Java饭馆 使用者可以通过getBean(对象ID) 获得Date对象,而不需要自己去new ...

  10. [OpenCV-Python] OpenCV 中的图像处理 部分 IV (五)

    部分 IVOpenCV 中的图像处理 OpenCV-Python 中文教程(搬运)目录 22 直方图 22.1 直方图的计算,绘制与分析目标 • 使用 OpenCV 或 Numpy 函数计算直方图 • ...