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. 第13章 模版方法模式(Template Method)

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

  9. NET设计模式 第二部分 行为型模式(15):模版方法模式(Template Method)

    摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要. 主要内容 1.概述 2.Template Method解说 3..NET中的Te ...

随机推荐

  1. css之overflow

    也说css之overflow:细探之下有意想不到的结果 2016-11-5 滴滴出行·DDFE 作者:dolymood overflow 是一个非常常用的 CSS 属性,一般来说会认为很简单,其实细究 ...

  2. BZOJ 3670 && BZOJ 3620 && BZOJ 3942 KMP

    最近感到KMP不会啊,以前都是背板的现在要理解了. #include <iostream> #include <cstring> #include <cstdio> ...

  3. C++ pair用法

    Pair类型概述 pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同 1.定义(构造): 1 pair<int, double> p1; //使用默认构造函数 2 pair ...

  4. Deploy .Net project automatically with MsBuild and MsDeploy (0)

    I will use a example of my project to show how to use MS Build and MS Deploy in a real project and s ...

  5. ubuntu切换java版本

    众所周知,ubuntu经常需要安装不同的java版本,他们之间的切换就是一个很大的问题 1.Chose another Java loader: sudo update-alternatives -- ...

  6. php之array_column 的使用

    听说只有大牛级的高工才知道的函数array_column () 讲真,我才知道. (PHP 5 >= 5.5.0, PHP 7) array_column - 返回数组中指定的一列 说明 arr ...

  7. 【Matlab&amp;Mathematica】对三维空间上的点进行椭圆拟合

    问题是这样:比如有一个地心惯性系的轨道,然后从轨道上取了几个点,问能不能根据这几个点把轨道还原了? 当然,如果知道轨道这几个点的速度的情况下,根据轨道六根数也是能计算轨道的,不过真近点角是随时间变动的 ...

  8. ElasticSearch(6.2.2)的java API官方文档的总结 (三)

    一 : SearchRequest用于任何与搜索文档,聚合和建议有关的操作,并且还提供了对生成的文档进行高亮显示的方法. 在最基本的形式中,我们可以向请求添加一个查询:    1:添加一个Search ...

  9. MT【308】投影的定义

    已知向量$\overrightarrow{a},\overrightarrow{b}$满足:$|\overrightarrow{a}|=2$,向量$\overrightarrow{b}$与$\over ...

  10. MDD Cup 2017 小记

    http://blog.csdn.net/zhangzhengyuan123123/article/details/78971298