OOD是OOA方法的延续,其基本思想包括抽象、封装和可扩展性,其中可扩展性主要是通过继承和多态来实现。在OOD中,数据结构和在数据结构上定义的操作算法封装在一个对象之中。由于现实世界中的事物都可以抽象出对象的集合,所以OOD方法是一种更接近现实世界、更自然的系统设计方法。
设计软件类
类封装了信息和行为,是面向对象的重要组成部分,它是具有相同属性、方法和关系的对象集合的总称。在系统中,每个类都具有一定的职责,职责是指类所担任的任务。一个类可以有多种职责,设计得好的类一般至少有一种职责,在定义类时,将类的职责分解为类的属性和方法,其中属性用于封装数据,方法用于封装行为。设计类时OOD中最重要的组成部分,也是最复杂和最耗时的部分。
1.实体类
实体类映射需求中的每个实体,实体类保存需要存储在永久存储体中的信息。实体类通常都是永久性的,它们所具有的属性和关系是长期的,有时甚至在系统的整个生存周期都需要。
实体类是对用户来说最有意义的类,通常采用业务领域术语命名,一般来说是一个名词,在用例模型向领域模型转化中,一个参与者一般对应于实体类。通常可以从SRS中的那些与数据库表(需要持久存储)对应的名词着手来寻找实体类。通常情况下,实体类一定具有属性,但不一定有操作。
2.控制类
控制类是用于控制用例工作的类,一般是由动宾结构鹅短语(“动词+名词”或“名词+动词”)转化来的名词,例如,用例“身份验证”可以对应于一个控制类“身份验证器”,它提供了与身份验证相关的所有操作控制类用于对一个或几个用例所特有的控制行为建模,控制对象(控制类的实例)通常控制其他对象,因此,他们的行为具有协调性。
控制类将用例的特有行为进行封装,控制对象的行为与特定用例的实现密切相关,当系统执行用例的时候,就产生了一个控制对象,控制对象经常在其对应的用例执行完毕后消亡。通常情况下,控制类没有属性,但一定有方法。
3.边界类
边界类用于封装在用例内、外流动的信息或数据流。边界类位于系统与外界的交接处,包括所有窗体、报表、打印机和扫描仪等硬件的接口,以及与其他系统的接口。要寻找和定义边界类,可以检查用例模型,每个参与者和用例交互至少要有一个边界类,边界类使参与者能与系统交互。边界类是一种用于对系统外部环境与其内部运作之间的交互进行建模的类。常见的边界类有窗口、通信协议、打印机接口、传感器和终端等。实际上,在系统设计时,产生的报表都可以作为边界类来处理。
边界类用于系统接口与系统外部进行交互,边界对象将系统与其外部环境的变更(例如,与其他系统的接口变更、用户需求的变更等)分隔开,使这些变更不会对系统的其他部分造成影响。通常情况下,边界类可以既有属性也有方法。
面向对象设计原则
对于OO系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高系统的可维护性和可复用性,是OOD需要解决的核心问题之一。在OOD中,可维护性的复用是以设计原则为基础的。常用的OOD原则包括开闭原则、里氏替换原则、依赖倒置原则、组合/聚合复用原则、接口隔离原则和最少知识原则等。这些设计原则首先都是面向复用的原则,遵守这些设计原则可以有效地提高系统的复用性,同时提高系统的可维护性。
1.开闭原则
开闭原则是指软件实体应对扩展开放,而对修改关闭,即尽量在不修改原有代码的情况下进行扩展。这里的“实体”可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。
应用开闭原则可扩展已有系统,并为之提供新的行为,以满足对软件的新需求,使变化中的系统具有一定的适应性和灵活性。对于已有的软件模块,特别是最重要的抽象层模块,不能再修改,这就使变化中的系统有一定的稳定性和延续性,这样的系统同时满足了可复用性与可维护性。在OOD中,开闭原则一般通过在原有模块中添加抽象层(例如,接口或抽象类)来实现,它也是其他OOD原则的基础,而其他原则是实现开闭原则的具体措施。
2.里氏替换原则
里氏替换原则由Barbara Liskov提出,其基本意思是,一个软件实体如果使用的是一个基类对象,那么一定适用于其子类对象,而且觉察不出基类对象和子类对象的区别,即把基类全部替换成他的子类,程序的行为没有变化。反过来则不一定成立,如果一个软件实体适用的是一个子类对象,那么它不一定适用于基类对象。
在运用里氏替换原则时,尽量将一些需要扩展的类或者存在变化的类设计为抽象类或者接口,并将其作为基类,在程序中尽量适用基类对象进行编程。由于子类基础基类并实现其中的方法,程序运行时,子类对象可以替换基类对象,如果需要对类的行为进行修改,可以扩展基类,增加新的子类,而无需修改调用该基类对象的代码。
3.依赖倒置原则
依赖倒置原则是指抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。在程序代码中传递参数时或在组合(或聚合)关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明和方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口和抽象类中声明过的方法,而不要给出多余的方法,否则,将无法调用到子类中增加的新方法。
实现开闭原则的关键是抽象化,并且从抽象化导出具体实现,如果说开闭原则是OOD的目标的话,那么依赖倒置原则就是OOD的主要机制。有了抽象层,可以使得系统具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样,如果系统行为发生变化,则只需要扩展抽象层,并修改配置文件,而无需修改原有系统源代码,在不修改的情况下来扩展系统功能,满足开闭原则的要求。依赖倒置原则是COM、CORBA、EJB、Spring等技术和框架背后的基本原则之一。
4.组合/聚合复用原则
组合/聚合复用原则又称为合成复用原则,是在一个新的对象中通过组合关系或聚合关系来使用一些已有对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用其已有功能的目的。简单的说,就是尽量使用组合/聚合关系,少用继承。
5.接口隔离原则
接口隔离原则是指用多个专门的接口,而不使用单一的总接口。每个接口应该承担一种相对独立的角色,不多不少,不干不该干的事,该干的是都干。
6.最少知识原则
最少知识原则也称作迪米特法则(Law of Demeter)