第_9章-面向对象设计_第1页
第_9章-面向对象设计_第2页
第_9章-面向对象设计_第3页
第_9章-面向对象设计_第4页
第_9章-面向对象设计_第5页
已阅读5页,还剩152页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9章面向对象设计 本章计划学时 8 10学时 本章主要内容 设计体系架构分层模式包设计软件类设计软件类软件类的属性和方法为类添加方法泛化和关联的设计对象持久化和数据库设计原则和设计模式 9 1面向对象的设计 面向对象分析和设计基于相同的模型 一般认为没有严格的阶段性和很明显的界限 面向对象设计阶段还是有明确的目标 具体内容包括 设计软件体系结构 定义系统的高层划分 确定主要组件及其接口 详细设计软件类或接口 按照架构模式定义信息系统的边界类 控制类和实体类 详细设计类的属性和方法 设计程序执行的交互图 设计数据库接口 解决面向对象模型到数据库模型的过渡 9 2设计软件体系结构 分层模式包子系统和接口 9 2 1层 下层组件负责对上层组件提供服务 上层组件可以使用下层组件定义的服务 但下层组件对上层组件一无所知 层与层之间通常是不透明的 每一层都具有独立的职责 不同层的软件构件可以分布在多台机器上 也可以部署在同一台机器上 1 层的概念 自从C S出现之后 软件就被分层了 Client端的软件完成前台任务 Server端的软件完成后台任务 一般是DBServer Client使用Server端的服务 依赖于Server端自从Internet出现之后 软件进一步分层 Client端的软件 IE浏览器 完成输入输出任务 WebServer上的程序提供业务逻辑处理 后台DBServer完成数据的存取C S常被称为传统的两层 B S称为三层本书的分层将不包含有关系统软件 如IE DBMS等 仅讨论应用系统 2 分层模式 传统C S 无明显分层两层三层四层多层基本思想 将逻辑功能相似的类封装到一个组件中 比如都是用于数据库访问的类做成数据库访问组件 所有表达销售领域对象的类做成销售组件 传统的C S应用程序 界面窗口程序中包含所有的内容 如输入输出 界面逻辑控制 业务逻辑运算等 数据库 经典的三层结构 数据库 销售组件 支付组件 表示层 业务逻辑层 数据访问层 数据库访问组件 经典的三层结构 表现层 处理用户和信息系统之间的交互 可以是简单的命令行窗口 也可以功能完善的图形用户界面 胖客户端程序 如基于HTML的浏览器界面 瘦客户端程序 业务逻辑层 也称为领域层或应用层 是信息系统所有和领域相关的工作 如根据输入数据或已有数据进行计算 依赖于数据访问层获取数据或保存数据 类库形式 数据访问层 一般指与数据库的交互 主要责任是数据库记录的存取 如专门的数据访问类 简化的层次结构 表现层业务层 数据访问层甚至简化成没有分层 窗口程序 表现 业务逻辑 数据存储程序几乎不能重用 扩展的四层结构 表现层 等同于三层中的表现层 控制层 中介层 是表现层和领域层的中介层 也称应用控制器 主要表示业务逻辑中的工作流 一般针对于用例的事件流控制 此外还负责会话状态 数据的合成或分解等事务 领域层 业务逻辑中的领域类的集合 不包含复杂工作流 数据访问 数据映射层 负责将基于对象的领域层数据映射到数据库关系表中的记录 也称为数据持久层 可自行开发或采用持久化框架 模型视图控制器架构MVC 模型 即相关的数据 它是对象的内在属性视图 是模型的外在表现形式 一个模型可以对应一个或者多个视图 视图还具有与外界交互的功能控制器 是模型与视图的联系纽带 控制器提取通过视图传输进来的外部信息转化成相应事件 然后由对应的控制器对模型进行更新 相应的 模型的更新与修改将通过控制器通知视图 保持视图与模型的一致性 3 多层的物理配置 由于应用软件封装成不同层次的独立组件 这给软件部署带来了灵活性 物理一层 所有应用软件的组件都安装配置在一台机器上 比如全部Web程序都在Web服务器上物理两层 应用软件的组件配置在两台机器上 比如一部分安装在客户端 另一部分配置在应用服务器上物理多层 客户端 一台或多台应用服务器 数据库服务器 即多台服务器的方式 这是分布式结构的一种形式 4 多层体系结构的动机 客户对数据的访问通过中间层进行了隔离 数据库的安全性提高了应用程序被分布部署在多个物理节点上 从而增强了处理大量的用户负载或计算任务的能力 系统可靠性和响应速度得到了提高业务逻辑处于不同的中间服务器 当业务规则变化后 客户端程序基本不做改动 而且某一层的改动不会影响其他层 这也意味着更好的重用和可维护性将不同层的开发任务在开发者之间适当地分配 有效地利用开发人员的专长和开发技巧 并且能够提高并行开发能力 9 2 2包 包 package 是一种逻辑分组手段 可以取UML模型中的任何一种事物 将相关成分聚在一起 以构成更高层的组织单元 包 最常用的方法是将类以包为单位进行分组 比如上一节提到的层 每一层中的所有类组成一个包 一个包可以包含其他的包 高层包被分成若干子包 子包又可以在分成更小的包 但在Java中 包还指代了物理的组织手段 如何分包 分包 软件类的分组 有两种原则 共同封闭原则 CommonClosurePrinciple 一个包中的各个类应该是由于相似的原则而改变 即将一组职责相似 但以不同方式实现的类归为一个包中 比如按照层来进行分包就是这种类型 共同复用原则 CommonReusePrinciple 一个包中的各个类应该一起被复用 复用其中一个可能需要同时考虑同一个包中的其他协作类 通常和业务功能相关 包图 包图用来描述包及其依赖关系 当表现层包中的类要使用领域包中的领域类提供的服务时 表示包就依赖于领域包 9 2 3子系统 当按照业务功能或管理职能组织包 并对这样的包进行彻底的封装实现后 一个高层的具有特定功能的可以运行的独立构件就产生了 称为子系统 subsystem 子系统具有自身独立的功能 是物理的具体软件单位 而包只是软件对象的逻辑组织方式子系统对外可以提供有限的接口 只要接口不改变 不管子系统内部发生什么变化 也不会影响到依赖于该子系统接口的其他子系统 子系统及其关系使用构件图描述 子系统的关系 财务子系统将内部操作进行了封装 但对外提供必要的接口 比如一组函数 销售子系统在执行销售业务过程中可以使用该接口对销售数据执行某些财务操作 对于销售子系统而言 依赖的是财务子系统的接口 并不需要关心财务子系统的具体实现 9 3设计软件类 软件类是设计阶段中讨论的对象和类 也称为设计类 软件类的设计的依据 来源于分析模型中的领域类 它们通常是现实事物或概念的抽象 这些类要转换为软件世界中的类 能够通过OOP实现计算机操作需要的类 比如为了完成用例所描述的功能 需要添加一些窗口界面类 复杂用例可能涉及到多个领域类的协作 添加控制类实现部分复杂控制流 9 3 1根据分层设计软件类 从分析模型的领域类导出设计阶段中的实体类增加边界类和控制类完成程序的交互和控制 为了分辨出类的这三种不同类型 可以采用UML提供的扩展机制 构造型 stetreotype 及其表达符号来定义模型元素构造型 Rose中不同构造型的图符 系统边界 对象行为的控制和协调 系统服务和信息 分层的软件类协作实现一个用例 1 边界类 边界类的职责是完成系统与其参与者之间的交互 接收来自用户和外部系统的信息与请求将信息与请求提交给用户和外部系统通过用例图可以得知每个边界类至少应该与一个参与者有关 参与者类型不同 边界类的设计也不同边界类包括屏幕窗口 通信接口 打印机接口 传感器 终端以及专用API 应用程序编程接口 等软件对象 对于图书馆系统来说 参与者都是系统用户 因此边界类只有窗口界面这一种形式 假如考虑提供馆际互借业务 那么系统就会产生与其他外部合作的图书馆系统的交互 这时与外部系统间的通信接口也是一种边界类 识别边界类 根据用例图 每个参与者与一个用例交互 必定导出一个边界类 2 实体类 实体类来源于领域模型中的类 实体类是一个软件对象 表示了领域对象的信息 以及具有与它所表示的信息有关的复杂行为 实体类反映的信息需要在系统中进行处理 并需要进行持久化存储 边界类和实体类的交互 边界类仅负责数据的输入和输出 不应承担和数据处理有关的业务逻辑边界类通过与实体类的交互 获得有关数据处理的结果 3 控制类 控制类代表协调 排序 事务处理以及对其他对象的控制 经常用于封装与某个具体用例有关的控制流 控制类处理和协调主要的动作和控制流 并将任务委派给其他对象 根据分层原则 控制类不封装与参与者交互有关的内容 也不封装与系统处理的长效持久的信息有关的问题 这些问题分别由边界类和实体类进行封装 识别控制类 当用例逻辑较为复杂 并涉及到多个实体类时 可以考虑采用控制类简化方案 控制类的职责合并给边界类 不同类的职责分配 向下依赖的关系 边界类负责与参与者的交互 输入数据 显示数据 为GUI的每个弹出式屏幕创建一个边界对象 控制类 可选 负责一个用例的事件流 或部分复杂数据流实体类负责数据的封装为每个领域类创建一个实体类 图书馆系统的界面类 图书馆系统的控制类 图书馆系统的实体类 9 3 2详细设计类的属性 属性类型和初值属性的类型和默认的初始值应该在设计模型中表示出来 类型和属性名之间用冒号隔开 等号之后写初值 选择的数据类型最好是目标语言中可用的 属性的可见性类中的每个属性可以有可见性定义 指定该属性可以被其他类利用的程度 UML定义了4种属性可见性 公有 public 受保护 protected 私有 private 包 package 图书馆类图 9 3 3建立用户界面原型 用户界面原型是一个草图 包含用例提到的系统和用户进行交互的必要元素界面原型不描述太多细节 通常包含以下内容 需要由用户输入到系统中的数据窗口或表格 需要由系统执行的操作按钮 系统应及时做出回应的事件 需要由系统输出给用户的数据窗口或消息 图书馆系统的借书界面 图书馆系统的还书界面 交互对话设计 9 3 4详细设计类的方法 每个软件类都有行为 这些行为是它们应承担的职责 也就是OOP中软件类的方法 职责是在对象设计过程中被分配给类的 该过程是用例驱动的通过对用例进行实现 可以构造出系统最重要的的动态模型 顺序图或通信图 完整的交互模型 交互模型的设计内容 对象职责的识别 意味着对象协作过程中消息的分发定义消息的完整格式将消息映射为类的操作 并在实现时转化为类的方法 职责完成的两种情况 职责是在对象设计过程中表现为分发给对象的消息 消息响应有两种情况 由某个对象独立承担 比如 计算超期天数 由一个Loan对象负责主要由一个对象负责 但该对象将职责进行了二次分配 即又发送了请求消息给其他对象 比如 负责计算订单总额 应该由一个Order对象负责 Order类受到该消息后 又请求OrderItem对象提供每个订单项的小计金额 数量 单价 职责的两种类型 由以上例子 可知职责有两种类型 行为型 即对象本身的方法 比如进行一项计算 被创建时的初始化 执行控制或协调的各项活动 了解型 对象应掌握的信息 比如对象自身的数据和属性 相关联的对象以及能够派生或计算的对象 如Loan类需要了解借出和归还日期 属性 以及所借资源的有关情况 即ResourceItem或ResourceTitle对象 关联对象 1 详细设计消息 消息的表达式语法return message parameter parameterType returnType如果类型信息非常明显或不重要的话 可以省略书写 如 reader getReader cardID String 消息的序号消息的次序用自小到大的顺序号来表示 按照消息的完成情况 消息可以有嵌套消息 嵌套消息的序号按照层次编号 所有嵌套的子消息都是服务于其上层消息 嵌套消息 嵌套消息含义与结构化方法中的模块调用相同结构化方法中模块都是单个的 没有分组 面向对象方法也强调模块的概念 但模块都有一个主人 对象OOD中的模块划分要解决两个问题 任务如何分解为子任务 各个任务应由谁承担 嵌套消息示例 计算超期罚金 最高不超过书价Loan对象在计算超期罚金时还需要获取资源的价格和罚金标准 因此向ResourceItem发送请求价格的消息 向FineRule发送超期罚金标准 而ResourceItem对象并不记录价格 因此请求价格的消息还需要发送给ResourceTitle对象 嵌套消息示例代码 Loan getTotalFine double titlePrice itemObject getTitlePrice finePerDay fineObject getOverDueFine doublefineAmount finePerDay this returnDate this dueDate if fineAmount titlePrice returnfineAmount elsereturntitlePrice ResourceItem getTitlePrice double returnitsTitleObject getPrice 返回消息 很多消息发送之后 消息的接收对象会在响应后产生一些结果回传给发送者 这就是返回消息 在UML交互图中 返回消息以虚线箭头线表示 为了简洁 一般省略返回消息 自身消息 有些消息是对象发给自己的 比如借书界面中要增加一个借阅项目 首先发送消息给控制类请求业务逻辑的处理 makeNewLoan消息 然后在窗口的列表中将新的借阅记录添加进来 addListItem 以备浏览和打印 添加列表的功能是界面类的职责 消息应发给窗口对象自身 图书馆顺序图示例 图书馆顺序图示例 图书馆顺序图示例 2 将消息转化为类的方法 交互图中的消息映射为接受消息的对象类的方法 操作 消息表达式中的参数和返回值等映射为类方法函数的参数和返回值同义词释疑 操作是关于行为的定义 方法是行为的实现 服务是行为的对外表现 消息是行为如何协作 它们用于不同的角度 场合 时机和模型中 但可以将它们认为是同义词 两类特殊的方法 对象创建方法UML中使用create消息表示对象实例化和初始化 例如 在C 和Java中 使用new操作符接构造函数的调用方式来实现实例的自动分配和初始化 常在设计类图中忽略相关的方法 如构造函数 属性存取方法在某些语言中 所有属性都声明为私有的 因此对每一个属性提供存取方法是一个常见的做法 例如getPrice和setPrice 为了模型的简洁 有时也省略这些方法 但在类图中可以通过属性的可见性来明确它们是否存在 图书馆实体类的方法 3 职责分配技术 CRC CRC卡片法是一种职责分配技术 CRC是类 职责 协作 Class Responsibility Collaboration 的简称 实践过程 首先为系统中每个类制作一张卡片选取一个用例 确定该用例的参与类取出上述确定的类卡片通过移动卡片来讨论类如何协作完成用例功能最后将形成的职责概念记录在类所在的卡片上 虽然它不是UML的组成部分 但也是一种快捷有效的的OO设计技术 9 3 5详细设计类或对象关系 设计四种关系的具体实现 泛化 类 关联 对象 依赖 对象 实现 类 1 泛化关系的设计 泛化在面向对象语言中使用继承来实现 继承机制实现了子类拥有父类特性的这一过程 泛化设计还有一个更重要的目的在于如何实现多态性 2 关联关系的设计 实现对象关联的一个简单策略就是 在关联的源类中声明一个属性来保存对目标类的实例的引用 这种属性称为关联属性或引用属性 根据关联的导航性 有单向关联和双向关联根据关联重数 有一对一 一对多和多对多关联 多对多关联通过建立关联类分解成1对多的关联限定关联 单向关联 publicclassResourceTitle privateReservationtheReserve privateMaptheItems newHaspMap 重数为0 1的关联 对于可选关联 源对象虽然定义了目标对象 但目标对象可能为空值 通常为null值 意味着没有关联对象 如某种书当前不存在预定记录 关联属性的值可以在源对象的构造函数中被创建 也可能在运行过程中通过方法赋值 publicclassResourceTitle privateReservationtheReserve 关联属性publicReservationgetReservation 获取关联对象returntheReserve publicvoidsetReservation Reservationrs theReserve rs 重数为多的关联 对于重数为多的关联 源对象应该能够管理多个目标对象 实现这种关联最简单的方法是使用开发语言提供的类库中的容器类来保存多个对象引用 如Java中的Vector Map类 Net中的Collection类等 示例代码如下 publicclassResourceTitle privateMaptheItems newHaspMap 集合关联属性publicvoidaddItem StringitemID 对象也可作参数ResourceItemaCopy newResourceItem itemID theItems put itemID aCopy publicvoidremoveItem StringitemID theItems remove itemID 双向关联 当关联双方需要相互都能访问到对方时 就是双向关联 比如Loan能知道所借的是哪一个ResourceItem 并且ResourceItem能够访问到对应的Loan 具体实现有多种办法 以下代码是一种示例 publicclassResourceItem privateLoantheLoan 关联属性publicvoidaddLoan Loanloan 建立双向关联theLoan newLoan this publicclassLoan privateResourceItemtheItem 关联属性publicLoan ResourceItemr Loan的构造函数theItem r 建立和ResourceItem的关联 关联的创建或解除 关联可以在对象一产生就已经存在 也可以在运行期间动态建立 对于那些比较持久并且不会发生变化的关联 或者具有很强归属关系的聚集关联 一般在主对象的构造函数中创建关联对象或记录下关联对象的引用较为松散的对象关联 一般当某项业务逻辑发生时 两个对象的关联才被确立 可以设计特定方法建立或解除关联 动态创建关联举例 publicClassCarprivateDrivertheDriver publicvoidassignDriver Driverdr theDriver dr Carc1 newCar 京B58888 红旗 Driverd1 NewDriver Wang Driverd2 NewDriver Zhao c1 assignDriver d1 建立c1和d1之间的关联 c1 assignDriver d2 建立c1和d2之间的关联 c1和d1的关联被解除 9 3 6设计对象的可见性 对象的可见性 visibility 是一个对象看见或拥有另一个对象引用的能力 当设计交互图时 可见性是对象协作得以实现的必要条件 当B对于A具有可见性时 对象A才能够发送消息给对象B 以请求B的某项服务 从对象A到对象B有以下四种常见方式 属性可见性参数可见性局部可见性全局可见性 属性可见性 当B是A的一个属性时 从A到B的属性可见性就存在了 在面向对象设计中 为实现关联必须增加关联属性 就是使用属性可见性的典型情况 这是一种容易理解也最常见的可见性形式 参数可见性 当B作为A的一个方法的参数被传递时 就存在了从A到B的参数可见性 这是一个相对临时的可见性 因为参数仅存活于所在方法的作用域内 局部可见性 当B被声明为A的一个方法内的局部对象 从A到B就具有了局部可见性 这也是一种相对临时的可见性 全局可见性 当B对A是全局的 从A到B的全局可见性就存在了 在面向对象系统中 全局可见性是不常见的形式 获得全局可见性的简单方法是将一个对象实例赋给一个全局变量 或使用单子模式 singleton 即为全局对象类定义一个静态方法 如getInstance 来返回该类的单个实例 这样所有其他对象只要使用该方法就可以获得一个全局 单一的对象 使用UML表示可见性 在UML中 属性可见性通常代表着对象的关联关系 因为关联是对象间维持得较为长久有深层含义的关系 一个对象在其整个生存周期中都能方便地由关联属性来获得关联对象 参数可见性和局部可见性都是瞬时并且在局部发生作用的全局可见性表达的是系统中的共享对象 不具备与特定对象的本质关联 第一种在UML表示为实线的对象关联关系 后三种可见性在UML中被定义为对象之间的依赖关系 使用虚线箭头来表示 9 3 7完整顺序图的绘制 掌握基本概念后 对每个用例的实现过程进行详细设计 一边构思职责分配 一边绘制顺序图 如何画顺序图 从用例描述中选择主要actor和发起事件 选择实现用例所需的基本显示屏幕 即边界对象 选择一个用例控制者 基本控制对象 来处理边界对象和领域对象之间的通信 从而实现模型 视图分离选择出所有参与到用例中的领域类 实体对象 以上过程可以动态创建所需要的类 如何画顺序图 若用例涉及到任何的包含或扩展用例 则可根据需要为它们创建次级控制对象 确定实现用例所需的窗口数目 可根据需要为每个主要窗口创建一个次级边界对象 在顺序图中按如下次序列出这些对象 边界类对象 用例控制者 实体对象 以访问次序列出 以及按访问次序为准的次级控制对象和次级边界对象 如何画顺序图 根据如下类别来识别所有解决问题的操作 实例创建和析构关联形成属性修改计算改变状态显示或报表需求与外部对象或系统的接口 如何画顺序图 尽可能地根据任何已经存在的设计模式 来重新排列对象类之间消息的序列 命名每个消息并为其提供可选参数 9 3 8举例 一个用户登录的用例 系统中有多个用户每个用户属于一个用户组每个用户组有不同的授权权限有多种 如数据查询 数据添加 数据删除 数据修改等 登录用例 界面对象接受输入的用户名和密码用例控制对象根据用户名和密码进行权限验证用户对象确认用户是合法用户通过用户的用户组对象获得有关权限界面对象显示登录成功 不成功结果 分析阶段的顺序图 界面类 控制类 实体类 设计阶段的顺序图 组件 界面类操作代码 PrivateSubcmdOK Click DimctAsNewControl LoginControlIfcheckInput ThenIfct VerifyUser txtUserName Text txtPassword Text ThenMsgBox 成功登录 ElseMsgBox 登录失败 EndIfEndIfEndSub 验证输入是否完整 是否符合格式要求 边界类的职责PrivateFunctioncheckInput AsBoolean 有关检查代码 checkInput TrueEndFunction 控制类操作代码 PublicFunctionVerifyUser UserNameAsString PasswordAsString AsBooleanDimuserAsNewBusiness userDimgrAsNewBusiness GroupDimrgsAsNewCollectionVerifyUser FalseIfuser queryByUserName UserName ThenIfuser Password PasswordThenSetgr user getGroup 取得用户组Setrgs gr getGroupRights 取得用户组权限Ifrgs Count 0ThenVerifyUser True 成功EndIfEndIfEndIfEndFunction User类操作代码 PublicFunctionqueryByUserName userNameAsString AsBooleanDimrstAsNewADODB RecordsetDimsqlAsString strGroupNameAsStringqueryByUserName Truesql select fromT userwhereUserName userName rst Opensql mConnection adOpenStatic adLockReadOnly adCmdTextIfrst RecordCount 0ThenmUserName rst UserName mFullName rst FullName mPassword rst Password strGroupName rst GroupName Setgroup NewBusiness group 创建用户组对象group groupName strGroupNameElsequeryByUserName FalseEndIfrst CloseEndFunction User类的操作 取得用户的组对象PublicFunctiongetGroup AsBusiness groupSetgetGroup groupEndFunction Group类的操作代码 PublicFunctiongetGroupRights AsCollectionDimrgAsBusiness RightDimrstAsNewADODB RecordsetDimsqlAsStringDimrecCountAsIntegerSetrights NewCollectionsql select fromT grouprights T rightwhereGroupName mGroupName andT grouprights RightID T right RightID rst Opensql mConnection adOpenStatic adLockReadOnly adCmdTextIfrst RecordCount 0Thenrst MoveFirstDoWhileNotrst EOFSetrg NewRightrg rightID rst T right RightID rg rightDesc rst RightDesc rights Addrgrst MoveNextLoopEndIfrst CloseSetgetGroupRights rightsEndFunction 9 4对象持久化与数据库 软件中的对象在程序中定义的对象 在系统运行期间其生命周期包含创建 使用和消亡三个阶段 因为程序所有代码和数据在运行时载入到内存 程序运行结束它们都要从内存中释放 所以这些对象实例都是瞬时的或暂时性的 信息系统中的对象一个信息系统中的领域类指代了系统中有意义的事物 这些领域对象及其所承载的信息是长期的 甚至是永久的 这些持久对象就是指生存期可以超越软件的一次执行时间而长期存在的对象 软件对象如何持久化 持久化对象 持久对象就是指生存期可以超越程序的任意一次执行时间而长期存在的对象 比如新建了一名读者对象 程序结束后该读者的基本信息将转化为持久保存的读者数据 这个过程也是通常所说的 物化 反过来 持久后的数据需要取出并重新生成对象 这个过程称为 反物化 通常实体对象都会成为持久对象 实体类也称为持久类 9 4 1几种持久化方案 文件从文件查询有关数据来初始化对象或创建一个新对象 对象发生改变或需要保存 则将对象数据写入到文件中 如XML文件 但复杂灵活的数据存取和查询难以实现 面向对象数据库管理系统 OODBMS 一种理想的基于存储和管理永久对象的对象管理系统 只要程序员声明某个对象是永久的 OODBMS中数据库模型和对象模型一致 对象的存储 恢复 转换等问题由OODBMS自动解决 但目前尚未达到广泛应用的阶段 成熟的关系型数据库系统 RDBMS 关系型数据库以二维表中的一条记录来保存某个对象 记录的字段对应对象属性 继承关系或关联关系通过表之间的联系表现 对象与关系两个概念之间存在 阻抗 因此需要进行映射 该方案是目前最普及的选择 其他的存储机制还有层次数据库 网状数据库等等 持久化设计的步骤 确定持久类及其持久属性确定持久化方案设计XML文件模式 Schema 或设计关系数据库的模型根据持久化方案设计持久化方法或持久化组件 关系型数据库的持久化方案 在确定持久类及其持久属性之后 还要解决以下问题 实体类如何对应到关系中的表呢 类的继承关系和对象关联如何体现 关系数据库的操作总结起来就是CRUD操作 创建记录 Create 查询记录 Retrieve 修改记录 Update 和删除记录 Delete 这些操作应该由谁来实现 什么时候使用 对象实例是内存的一个单元 使用实例名来标识 表中的记录则采用唯一的主键码来识别 如何实现特定对象实例和记录的一一对应呢 9 4 2ORM设计问题 无论自己编写代码实现持久化 还是使用持久化组件 都要解决一个问题 那就是 对象与数据库的映射关系 采用关系型数据库实现对象的数据存储 这种映射也称为对象 关系映射ORM ObjectRelationalMapping ORM的设计包括 确定对象和表的映射关系确定软件实现构架 1 对象 关系的映射 类映射到表关联关系的映射继承关系的映射 持久类映射到表 在一个第三范式的关系数据库中 表中每一行 每个 元组 都被认为是一个对象 表中的列则对应于持久类的持久属性 注意 持久类也可能有临时属性 在没有其他关联类的简单情况下 这两种模型间的映射将会很简单 类的属性对应于列 其数据类型转换为列允许的数据类型之一 关联关系的映射 两个持久对象间的关联关系在OOAD中通常表现为一个对象存放了另一个对象的对象引用 也称为关联属性 而在表中则表现为外键 外键是一个表中的一列 其中存放所关联对象的主键值 对于对象关联中的特殊类型 组成聚集 因为整体对象和部分对象具有相同的生存周期 因此为了在数据模型中实现引用完整性 数据库详细设计时还需要实施删除约束 比如删除图书馆某个资源品种就必须同时删除所有的资源项 以及参照完整性的设计 Reader Loan 借阅 1 读者 读者编号 读者姓名 读者单位 当前限额借书记录 ID 读者编号 馆藏流水号 借书日期 到期日期 归还日期馆藏项 馆藏流水号 当前状态 ResourceItem 0 11 记载 继承关系的映射 三种可选方式 继承关系树的每个类对应一个表 使用不同的表来分别表示父类和子类 继承关系树的每个具体类对应一个表 将所有父类的属性复制为子类表中不同的列 父类不建立对应的表 继承关系树只对应一个表 使用一张表来描述父类和所有子类的属性 额外还需要增加一个列表示对象所属的子类型 Book Disc ResourceTitle 1 三个表 品种 ISBN 名称 作者 出版日期 价格 书籍 ISBN 开本光盘 ISBN 光盘类型 盘片数量 2 两个表 书籍 ISBN 名称 作者 开本光盘 ISBN 名称 作者 光盘类型 盘片数量3 一个表品种 ISBN 名称 作者 品种类别 开本 光盘类型 盘片数量 2 持久化软件架构设计 1 在领域层实现 即直接在实体类中编写SQL语句访问数据库 或者为了减少数据库操作的代码数量 编写一个公用的数据访问类 各实体类将组装好的SQL语句传递给该类以实现数据库访问 2 设计简单的数据映射层实现数据访问 即把SQL访问从业务逻辑中分离出来 放到独立的类中 当每个实体类映射为一张表时 可以为每个实体类建立一个数据访问类 一般包括数据查找方法以及更新 插入和删除方法 3 设计功能独立具有数据映射器的持久层 业务逻辑层完全不用了解数据的存储 应用程序中的对象通过设置与表的映射关系后 可以在开发人员对底层数据库及其模型毫不知情的情况下实现数据的持久化 映射关系通过数据映射器来具体实施 它是分离内存对象和数据库的一个软件层 其职责是在内存对象和数据库之间传递数据并保持它们彼此独立 三种设计方法的举例 参见用户权限的VB程序 实体类负责数据库的访问参见微软PetShop程序 数据库访问通过编写数据访问层的类来实现 比如业务层的类Order 有Insert getOrder方法分别完成保存和查询的功能 这些方法中使用了数据访问层的类来读写数据库网上可查阅Hibernate示例程序 代码中不需要编写SQL语句 9 5面向对象设计原则 设计原则结构化方法 低耦合 高内聚 模块化面向对象方法 封装 重用 SRP OCP DIP 为什么要讨论设计原则 设计良好的系统 容易理解 可变更性好 易于重用设计糟糕的系统如同腐化食物散发出臭味 smell 有以下症状 僵化性 rigidity 系统很难改变 即使一个简单的改动也会导致大量有耦合关联的其他部分的连锁反应 脆弱性 fragility 改变系统的某个部分会破坏许多无关的其他部分固化性 immobility 很难将系统分解成可供其他系统重用的部件 黏滞性 viscosity 当软件需要改动时 设计不容易保持稳定 逐渐脱离原形而走样 不必要的复杂性 needlesscomplexity 过分的或超前的设计不必要的重复性 needlessrepetition 大量代码重复 修改一处时 需要对每个重复副本一一修改 晦涩性 opacity 很难阅读理解 不能很好地表现出设计者的意图 设计原则 采用设计原则来帮助消除臭味 单一职责原则 TheSingleResponsibilityPrinciple 简称SRP 开放 封闭原则 TheOpen ClosePrinciple 简称OCP Liskov替换原则 TheLiskovSubstitutionPrinciple 简称LSP 依赖倒置原则 TheDependencyInversionPrinciple 简称DIP 1 单一职责原则SRP 即内聚性原则 高内聚原则可以从模块设计引申到类的设计 一个类承担的职责过多 任一个职责的变化可能会削弱或者抑制该类完成其他职责的能力 并影响到构建 测试和部署等活动 多个职责的耦合会导致脆弱的设计 当变化发生时 设计会遭到意想不到的破坏 职责过多的职工类 分离职责到不同的类 对 杂凑类 进行分解 2 开放封闭原则OCP 软件实体 类 模块 函数等 应该是可以扩展的 但是不可修改的 变化才是不变的真理 但通过设计使得系统能够适应改变又能保持相对稳定 避免僵化的设计 开放 封闭原则实现两个目标 对于扩展是开放的 openforextension 这意味着模块的行为是可扩展的 从而使其具有满足那些改变的新需求 对于更改是封闭的 closedformodification 当对模块进行扩展时 不必改动模块的源代码或二进制代码 如DLL库文件 自相矛盾吗 什么是不封闭 不开放 如下的模型可以处理月薪制和时薪制职工工资 如果还要增加一种职工类型 其计酬方式不同 如提成制 则必定要修改Employee类 如何改进 利用抽象机制封闭 Employee及其子类是封闭的开放 可以派生新的子类 实现新的需求 3 Liscov替换原则LSP 实现OCP的主要机制是抽象和多态 怎样设计最佳的继承层次 BarbaraLiskov在1988年首次提出LSP 子类型 subtype 必须能够替换掉它们的基类型 basetype 假设S是T的子类型 所有使用了T对象的程序 也称客户程序 用S对象替换T对象后 仍能成功执行 LSP是多态顺利实现的保证 从而使OCP成为可能 因为正是子类型的可替换性才使得使用基类的模块在无需修改的情况下就可以扩展 增加或修改任何一个子类型 基类不用修改 封闭 基类的使用者 客户程序 通过多态得到扩展或修改过的行为 开放 一个使用继承的例子 正方形是长方形的一种特例 会发生什么情况 正方形有独特的行为方式通过覆盖父类的有关方法来实现子类行为 客户程序如何能了解 长方形的使用者按照长方形的特点来调用SetWidth和SetHeight两个函数 并测试面积 代码如下 voidtestArea Rectangle 如果传递进来的是Square对象又会如何呢 显然会出现断言错误 测试失败 对于客户程序来说 模型中的层次结构是脆弱的 因为违反了LSP替换原则 Square对象和Rectangle对象的行为方式不相容 这样的抽象即使采用虚函数也无法实现子类对父类的替换 违反LSP替换原则 多态的使用是不安全的 4 依赖倒置原则DIP 高层模块不应该依赖于低层模块 二者都应该依赖于抽象 抽象不应该依赖于细节 细节应该依赖于抽象 结构化设计时 高层模块总是依赖于低层模块 面向对象的分层模式中也是高层的类依赖于底层的类 按照自上而下的依赖关系 高层的策略设置模块往往是无法重用的 如果设法让高层模块独立于低层模块 则实现重用就变为可能 依赖倒置原则的启发式建议是 依赖于抽象 具体做法是将高层需要的服务声明为抽象接口 高层使用这些接口 低层模块实现这些接口 使得高层不再依赖于低层 而是依赖于抽象接口 同样低层也依赖于抽象接口 传统的依赖层次 高层使用低层的对象及其服务 都依赖于抽象 设计抽象接口 上层类使用接口 下层类实现接口这样Button类也可以得到重用 也许是开关灯 也许是开关电视 根据创建具体对象完成多态的行为 如何遵守设计原则 设计原则不是死记硬背 而是要灵活运用一些成熟的设计模式可以帮助我们解决实际问题 并且符合设计原则 9 6设计模式 GRASP对象职责分配模式GRASP GeneralResponsibilityAssignmentSoftwarePattern 是一组通用的基本原则和惯用的设计方案 用来指导对象职责的分配和交互图的创建 OOAD经典著作 UML和模式应用 进行了总结和应用 GoF23种设计模式由四人组的专著 设计模式 一书总结了广为应用的23种设计模式 每种模式解决了一个特定问题 包括一组合适的对象和对象接口 以及对象间协作的方式 模式 模式在现实生活中随处可见 模式是对成功应用经验的总结与复用 模式无处不在 好莱坞电影模式社会题材 动作片 言情片 历史题材片 中国象棋开局当头炮 顺炮 列炮 屏风马 围棋布局星小目 三连星 中国流 宇宙流 古代行军布阵八阵图 天门阵 一字长蛇阵 建筑 服装 交通 社会 文化 诸多模式 计算机中的模式 如何在已排序的值列表中查找一个元素 1 将列表一分为二 将要查找的值与中间元素的值相比较 如果相等 就找到我们要查找的值 如过要查找的值小于中间元素的值 将中间点设置为列表的新的顶点 并再次将列表一分为二 如果要查找的值大于中间元素的值 将中间点设置为列表的新的尾点 然后再将列表一分为二 继续这种分割过程 直到列表不能再分为止 此时 如果要查找的值不再最后两个元素中 它就不在这个列表中 2 使用二分查找 9 6 1模式的定义 美国建筑设计大师ChristopherAlexander 在他出版的一本关于城市规划和建筑设计的著作 建筑的永恒方法 中 是这样描述模式的 模式是一条由三部分组成的规则 它表示了一个特定环境 一个问题和一个解决方案之间的关系 每一个模式描述了一个在我们周围不断重复发生的问题以及该问题解决方案的核心内容 这样 你就能一次又一次地使用该方案而不必做重复劳动 Eachpatterndescribesaproblemwhichoccursoverandoveragaininourenvironments andthendescribesthecoreofthesolutiontothatproblem insuchawaythatyoucanusethissolutionamilliontimesover withouteverdoingitthesamewaytwice ChristopherAlexander APatternLanguage 1977 设计模式名成为专业词汇 讨论设计方案时 使用模式名能简化描述 设计模式 是 优秀的设计范例从优秀设计方案中发现和总结出来的经验在实践中反复出现的设计问题的优秀解决方案设计者相互交流的基本术语 设计语言培养优秀设计师的一条捷径不是 面向对象设计的框架可供简单组合的设计元件发明创造出来的创新思路解决面向对象设计问题的完整方案 设计模式的基本要素 名称 用于助记 形象表示这个模式问题 这个模式可以解决什么问题解决方案 这个模式怎样解决这个问题的步骤与方法效果 使用这个模式与不使用这个模式有什么区别 它有什么优点和缺点 一个问题可以有多种解法 好的解法都可以找到很多种 每种都有优缺点 某个模式也不一定永远是最好的 设计模式的基本思想 1 软件是在不断进化的需求在不断改变 所以软件应该适应变化设计模式是为了让软件更加适应变化 有更多的可复用性 就是有变化时你不用从头重写一次这个软件如何适应变化 就应该封装变化 让变化的影响最小封装复杂性 提供简单的接口 设计模式的基本思想 2 遵守上述设计原则 松耦合针对接口编程 而不是针对实现编程继承 组合 委托 多态 参数化 9 6 2GoF设计模式 GangofFour 简称GoF 他们是 ErichGammaRichardHelmRalphJohnsonJohnVlissides著作 设计模式 23种GoF模式 GoF模式分类 1 根据模式的目的 用来完成什么工作的 创建型模式结构型模式行为型模式根据模式的作用范围 是处理类还是处理对象的 类模式对象模式 GoF模式分类 2 创建型模式创建型类模式将对象的部分创建工作延迟到子类创建型对象模式将它延迟到另一个对象中结构型模式结构型类模式使用继承机制来组合类结构型对象模式描述了对象间的组装方式行为型模式行为型类模式使用继承描述算法与控制法行为型对象模式则描述一组对象怎样协作完成单个对象无法完成的工作 GoF举例 State模式 1 修改LegoSystem源代码caseBLUE BlueProcess break LegoSystem ProcessColor switch color caseRED RedProcess break caseGREEN GreenProcess break caseYELLOW YellowProcess break State模式 2 目的 允许一个对象在其内部状态改变时改变其行为结构适用性 一个对象的行为取决于它的状态 并且它必须在运行时刻根据状态改变它的行为一个操作中含有庞大的多分支的条件语句 且这些分支依赖于该对象的状态 这个状态通常用一个或多个枚举常量表示State模式将每一个条件分支放入一个独立的类中 这使得可以根据对象自身的情况将对象的状态作为一个对象 这一对象可以不依赖于其他对象而独立变化 State模式 3 Yellow process Red process Green process LegoSystem color Color processColor Color process State模式 4 LegoSystem ProcessColor Color Process CColor public virtualvoidProcess voidCRed Process RedProcess voidCGreen Process GreenProcess voidCYellow Process Yellow

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论