面向对象设计
设计中的SoC 设计比较复杂时 任务被分隔开 只考虑一个问题,这个问题具有一定的独立性 用面向对象的思想设计软件 以数据为中心 2 2
设计中的SoC 设计的本质是用黑箱及其接口描述系统 每个部件通过其接口提供一些服务 相对来说,其他部件是这些服务的用户(客户) 客户只需了解服务的接口, 而实现细节对客户无关紧要 服务组件只管提供服务的实现, 不管客户如何应用 3 3 3
自顶向下设计与OOD 自顶向下设计 OOD: 函数是黑箱 客户只要知道函数接口即能使用之 函数实现细节被封装在函数定义中 对象是黑箱 对象的能力由类定义 类对外提供的接口即方法 方法的实现对外部客户是不重要的 4 4
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 考虑问题描述中的名词(事物) 这些事物有什么行为 例如:图中Point 5 5 5
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 对象信息 如:点的x,y坐标 6 6 6
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 确定接口 考虑问题描述中的动词(对象行为) 对对象数据的所有操作要在提供的方法中完成 点:显示、移动、读坐标、写坐标等 7 7 7
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 确定接口 复杂方法的自顶向下逐步求精 8 8
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 确定接口 复杂方法的自顶向下逐步求精 反复设计 可能会不断增加新类或方法 不能期待以线性、系统的方式设计程序 9 9 9
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 确定接口 复杂方法的自顶向下逐步求精 反复设计 尝试其他途径 会大量经历“尝试-失败”的过程 10 10 10
OOD设计指南 OOD: 对给定问题找出并定义一组有用的类的过程 确定有用的对象 确定实例变量 确定接口 复杂方法的自顶向下逐步求精 反复设计 尝试其他途径 力求简单 11 11 11
类与模块化 复杂程序的模块化设计 功能模块不太适合复杂数据的处理 类模块独立性更高,可重用性更好 功能分解:利用子程序(如函数)概念,以过程为中心设计功能模块 数据分解:利用类的概念,以数据为中心设计数据模块 功能模块不太适合复杂数据的处理 类模块独立性更高,可重用性更好 类定义可以提供给任何程序使用 很多OO语言都提供类库 12
如何表示任意复杂的数据 数据的复杂性表现在 两种复杂性混合:用"对象的集合"来刻画 数量大:用集合体数据类型来表示 有内部深层结构:用类来表示 两种复杂性混合:用"对象的集合"来刻画 >>> people = [p1, p2] >>> for p in people: p.whatName() p.howOld(2013) 13
编程实例: 壁球 回顾 模拟两位球员的壁球比赛,记录比赛统计结果 需求变化 还需要统计shutout的次数(一方7分,一方0分) 14
编程实例: 壁球 对象: 一局比赛: 输入两个球员的技术水平, 提供play() RBallGame 得分统计: 统计比赛结果, 提供update(), printReport() SimStats
编程实例: 壁球 对象: 主程序核心代码: 一局比赛: RBallGame 得分统计: SimStatus stats = SimStats() for i in range(n): theGame = RBallGame(probA,probB) theGame.play() stats.update(theGame) 16
编程实例: 壁球(续) 设计一个类时会获得其他类的设计思路 各类间的关系可用图来表示 例如:实现SimStats的update(aGame)时,需要aGame的分数, 由此想到RBallGame类应提供getScores方法 又如:实现RBallGame时, 发现技术是属于球员而非比赛的, 因此应设计Player类 各类间的关系可用图来表示 17 17 17
编程实例: 壁球(续) 完整程序:objrball.py 18
编程实例:Dice Poker 游戏规则: 玩家开始时有$100 每轮花$10进行游戏 先投掷一手5个骰子 然后有两次机会重掷部分或全部骰子 最后根据右表结帐 两对 $5 三同 $8 一对加三同 $12 四同 $15 顺子(1-5或2-6) $20 五同 $30 19
编程实例:Dice Poker 图形界面要求 显示余额 玩家破产时自动终止 玩家也可选择退出 提示程序状态及用户如何响应的信息 20
编程实例: Dice Poker(续) 模型-视图(model-view)设计方法 将复杂程序分解为模型和用户界面 模型是程序的核心(程序的逻辑) 视图是模型状态的展现 如:收音机,投资收益 21
编程实例: Dice Poker(续) 模型-视图(model-view)设计方法 分开的好处: 对同一模型,容易改变视图 先考虑问题如何解决,然后再考虑如何呈现给用户 22
编程实例: Dice Poker(续) 模型-视图(model-view)设计方法 本例中: 注:文字界面简单,适合调试; 游戏模型: PokerApp类 游戏界面: TextInterface或GraphicsInterface类 注:文字界面简单,适合调试; 图形界面复杂,交互性好 23
编程实例:Dice Poker(续) 实现模型 低层对象:类Dice 高层对象:PokerApp 构造器: 初始化Dice对象集合体 rollAll: 对5个骰子赋随机值 roll: 对部分骰子赋随机值,其他不变 values: 返回骰子当前值 score: 返回骰子的得分(金额) 高层对象:PokerApp 24
编程实例:Dice Poker(续) 实现界面 文本界面:测试用 GUI界面 25
OO概念:封装 将数据以及相关操作打包在一起的过程. 封装的结果就是对象概念. 世界是相互作用的对象构成的. 封装使”定义”与”使用”的SoC成为可能. 封装使得代码重用成为可能(e.g. button) 要会使用类库 26
OO概念: 多态性 给对象发了消息, 具体做什么取决于该对象的类型. 例如: obj.draw(win)对不同图形对象obj将画出不同的图形. 27
OO概念: 继承 可以从现有的类出发, 定义新类 超类与子类 子类继承超类的变量和方法, 并且另有自己的变量和方法 好处: 代码重用 28
作业 Write a program that simulates an Automatic Teller Machine (ATM). Since you probably don’t have access to a card reader, have the initial screen ask for user id and a PIN. The user id will be used to look up the info for the user’s accounts (including the PIN to see if it matches what the user types). Each user will have access to a checking account and a savings account. The user should able to check balances, withdraw cash, and transfer money between accounts. Design your interface to be similar to what you see on your local ATM. The user account information should be stored in a file when the program terminates. This file is read in again when the program restarts.
End 30