[python 译] 基于面向对象的分析和设计

时间:2021-07-10 07:48:47

[python 译] 基于面向对象的分析和设计

 

[python 译] 基于面向对象的分析和设计

2 引言

 

2.1 译者

特别在编程语言的学习过程中, 通常会纠结在语言本身的细节中, 然后发现学习的过程变得越来越枯燥, 以至于最后放弃了这门才刚刚起步的语言, 投身到新的一个轮回中. 因为他们忘记了: 快乐来自于创造. 当然起先掌握一门语言还是很有必要的.

2.2 作者

我(以下文中的我均指作者)将描述在运用python的语言建立一些东西的过程, 这些描述更适用于运用python面向对象的特性的时候. 这里, 我所说的过程是面向通常问题时, 你需要一步一步完成的步骤, 当然这并不意味着你需要奴役于这些条条框框. 它通常是解决很多编程问题的一个起点, 但并不是唯一的一个方法. 你可以选择, 也可以不选择.

具体的过程如下:

  1. 用写和绘画的方式, 对问题进行描述
  2. 从第一步中提取出关键的概念, 然后对它进行研究
  3. 对这些关键概念建立类的层次关系和对象图
  4. 编写相应的类代码和测试代码
  5. 重复进行改善

整个过程是从上至下的, 也就是说, 它是从一个很细微的, 很抽象的一个想法出发, 慢慢地通过不停地改善逐渐成为能够编写的实例.

首先, 我会写出关于这个问题的所有东西, 并尽自己的能力进行思索. 也许我会画一个或两个示意图, 也许是像地图一样的东西, 甚至给自己写一系列描述该问题的邮件. 这让我有一个方式来表达关键性概念, 也让我清楚自己对这个问题有多少的了解.

然后, 我会浏览这些纪录, 图像以及相关的描述, 并且将最主要的部份提取出来. 有一个简单的方式能够实现它: 简单的制作一个 名词动词 的列表, 然后给出两者之间的关系. 这些给了我一个很好的列表, 有助于我在下一步中, 对于类名, 对象名和方法名的确定. 我保留这份由概念组成的列表, 然后对于任何一个我不能够理解的内容进行改善.

当我拥有这样一份列表的时候, 我可以创建一个简单的由概念组成的大纲或是树, 以及它们如何成为类. 你通常可以拿着你的名词单, 并开始问自己 "这个名词是不是和别的, 意思相同? 这意味着它们有一个相同的父类, 那么这个父类叫什么呢?" 不断地重复提问回答地过程, 直到建立一个类关系图, 树图. 然后拿着你的动词表, 看这些动词是否是类的函数名, 然后将其放入到树图中.

当类的层次图建立后, 我开始用代码写基本的框架, 只有类名以及属于它们的函数, 没有其他内容. 然后写运行该程序的测试, 并且确信刚建立的类是有意义的, 并且能够正确地执行. 有时, 我会先写测试, 有时, 一边写测试一边写代码, 直到完成所有的工作.

最后, 不断的重复, 不断的改善, 在我添加更多的实现的时候让它变得越来越清晰. 如果我在某个概念或是某个问题无法解决的时候, 我会停下来, 再继续之前会重复上述的过程, 直到这些概念变得清晰.

接下来, 我会将上述的过程运用到一个游戏引擎实现的过程中.

3 The Analysis of the Simple Game Engine

这个将要实现的游戏叫做: Gothons from Planet Percal #25, 是一个小型的太空冒险游戏.

3.1 Write or Draw About the Problem

我将给出对游戏的一个简单的描述:

外星人入侵了一艘太空船, 我们的英雄为了能够成功的逃入救身舱驶向地球, 不得不穿过迷宫般的房间. 这个游戏非常像Zork或是其他冒险类游戏, 通过文字输出, 以及有趣的死亡方式. 这个游戏将包含运行所有房间或是场景的引擎. 当完家进入一个房间的时候, 都会出现相应的描述, 并且告诉引擎当出了这个地图后, 哪个房间将被运行.

此刻, 对于这个游戏有了一个基本的描述, 以及它将如何运行, 因此让我来描述一下每个场景:

死亡, Death
当完家死亡时会被触发, 应具有一定的娱乐性
*过道, Central Corridor
那是一个开始点, 有一个Gothon已经站在了那里, 在开始之前首先要击败一个玩笑
激光武器库, Laser Weapon Armory
英雄能在这里获取中子炸弹, 用于在进入救身舱之前引爆. 它有一个输入盘, 需要猜测数字
桥, bridge
另一个有Gothon的战争场景, 英雄将在那里放置炸弹
救身舱, escape pod
当且仅当猜对正确的救身舱之后, 才能够逃离

现在, 我可能会根据上述的描述绘制地图, 或是为每个房间写更多的描述, 任何进入我的思维, 并且与这个问题相关的内容.

3.2 Extract Key Concepts and Research Them

列出相关的名词:

  • 外星人, alien
  • 玩家, player
  • 船, ship
  • 迷宫, maze
  • 房间, room
  • 场景, scene
  • Gothon, (应该是外星人的名字, 译者)
  • 逃身舱, escape pod
  • 地球, planet
  • 地图, map
  • 引擎, engine
  • 死亡, death
  • *过道, central corridor
  • 激光武器库, laser weapon armory
  • 桥, the bridge

这里先跳过对动词进行列表.

此刻, 你应该研究每个概念, 并弄清楚每个不了解的概念. 例如, 我应该玩一些类似的游戏, 保证自己能够知道它是怎么运作的. 我应该研究船是怎么设计的, 以及炸弹是怎么工作的. 也许, 我还要研究一些技术性问题, 如, 如何将游戏状态存储到数据库中. 当我完成这些研究之后, 我应该基于新的描述重新回到第一步, 提取新的概念.

3.3 Create a Class Hierarchy and Object Map for the Concepts

当我到建立类层次关系这一步的时候, 开始向自己问 "什么和其他的东西相近呢?" "什么是其他东西的替代词呢?"

我发现当我需要做某些事情的时候, "room"和"scene"可以认为是相同的. 我选择了"scene". 然后我发现像"Central Corridor"这样的特殊的房间其实就是"scene". 我也将"Death"成为"Scene", 这也解释了我为什么在一开始选择了"scene"而没有选择"room". "maze"和"map"也是相同的, 我选择了"map". 由于我不相要制作一个战争系统, 所以我将"Alien"和"player"忽略了, 并将它们先保留着. 同时, "Planet"也可以成为一种特殊的"scene".

随后, 建立了类的层次关系:

  • Map
  • Engine
  • Scene
    • Death
    • Central Corridor
    • Laser Weapon Armory
    • The Bridge
    • Escape Pod

下面给出相应的动词, 用来描述不同情况下需要怎样的行为. 通过描述知道: 我需要运行引擎, 从地图中进入到下一个场景, 然后打开场景, 并且进入场景. 于是:

  • Map
    • nextscene
    • openingscene
  • Engine
    • play
  • Scene
    • enter
    • Death
    • Central Corridor
    • Laser Weapon Armory
    • The Bridge
    • Escape Pod

我将enter只放在了scene下面, 因为所有的场景都可以从"scene"中继承

译者添加:

class Map {
next_scene()
opening_scene()
} class Engine {
play()
} class Scene {
enter()
} Death -up-|> Scene
CenterCorridor -up-|> Scene
LaserWeaponArmony -up-|> Scene
TheBridge -up-|> Scene
Escape -up-|> Scene

[python 译] 基于面向对象的分析和设计

3.4 Code The Classes and a Test to Run Them

接下来, 我通常会将上面的three复制到我的源代码文件中, 然后按照它编写相应的类. 下面是一个简单的例子, 说明编写的类的初始状况:

class Scene(object):

    def enter(self):
pass class Engine(object): def __init__(self, scene_map):
pass def play(self):
pass class Death(Scene): def enter(self):
pass class CentralCorridor(scene): def enter(self):
pass class LaserWeaponArmory(Scene): def enter(self):
pass class TheBridge(Scene): def enter(self):
pass class EscapePod(Scene): def enter(self):
pass class Map(object): def __init__(self, start_scene):
pass def next_scene(self, scene_name):
pass def opening_scene(self):
pass a_map = Map('central_corridor')
a_game = Engine(a_map)
a_game.play()

接下来就是重复以及完善了.

4 The Code for "Gothons from Planet Percal #25"

完整的代码示例请参见原文, The Code for "Gothons from Planet Percal #25"

Date: 2014-04-21 Mon

Author: Zhong Xiewei

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0