OOAD - 实施策略
实现面向对象的设计通常涉及使用标准的面向对象编程语言(OOPL)或将对象设计映射到数据库。 在大多数情况下,两者都涉及。
使用编程语言实现
通常,将对象设计转换为代码的任务是一个简单的过程。 任何面向对象的编程语言,如 C++、Java、Smalltalk、C# 和 Python,都包含表示类的规定。 在本章中,我们使用 C++ 举例说明了这一概念。
下图显示了 Circle 类使用 C++ 的表示形式。
实施关联
大多数编程语言不提供直接实现关联的构造。 因此,实施关联的任务需要深思熟虑。
关联可以是单向的,也可以是双向的。 此外,每个关联可以是一对一、一对多或多对多。
单向关联
为了实现单向关联,应注意保持单向性。 不同重数的实现如下 −
可选关联 − 这里,参与对象之间可能存在也可能不存在链接。 例如,在下图中"客户"和"活期账户"的关联中,客户可能有也可能没有活期账户。
为了实现,当前帐户的对象作为属性包含在客户中,该属性可以为 NULL。 使用C++实现 −
class Customer { private: // attributes Current_Account c; //an object of Current_Account as attribute public: Customer() { c = NULL; } // assign c as NULL Current_Account getCurrAc() { return c; } void setCurrAc( Current_Account myacc) { c = myacc; } void removeAcc() { c = NULL; } };
一对一关联 − 这里,一类的一个实例恰好与关联类的一个实例相关。 例如,部门和经理具有一对一的关联,如下图所示。
这是通过在 Department 中包含一个不能为 NULL 的 Manager 对象来实现的。 使用C++实现 −
class Department { private: // attributes Manager mgr; //an object of Manager as attribute public: Department (/*parameters*/, Manager m) { //m is not NULL // assign parameters to variables mgr = m; } Manager getMgr() { return mgr; } };
一对多关联 − 这里,一类的一个实例与相关类的多个实例相关。 例如,考虑下图中 Employee 和 Dependent 之间的关联。
这是通过在 Employee 类中包含一个 Dependents 列表来实现的。 使用C++ STL列表容器实现 −
class Employee { private: char * deptName; list <Dependent> dep; //a list of Dependents as attribute public: void addDependent ( Dependent d) { dep.push_back(d); } // adds an employee to the department void removeDeoendent( Dependent d) { int index = find ( d, dep ); // find() function returns the index of d in list dep dep.erase(index); } };
双向关联
要实现双向关联,需要维护两个方向的链接。
可选或一对一关联 − 考虑项目和项目经理之间具有一对一双向关联的关系,如下图所示。
使用C++实现 −
Class Project { private: // attributes Project_Manager pmgr; public: void setManager ( Project_Manager pm); Project_Manager changeManager(); }; class Project_Manager { private: // attributes Project pj; public: void setProject(Project p); Project removeProject(); };
一对多关联 − 考虑部门和员工之间具有一对多关联的关系,如下图所示。
使用C++ STL列表容器实现
class Department { private: char * deptName; list <Employee> emp; //a list of Employees as attribute public: void addEmployee ( Employee e) { emp.push_back(e); } // adds an employee to the department void removeEmployee( Employee e) { int index = find ( e, emp ); // find function returns the index of e in list emp emp.erase(index); } }; class Employee { private: //attributes Department d; public: void addDept(); void removeDept(); };
将关联实现为类
如果关联具有关联的某些属性,则应使用单独的类来实现它。 例如,考虑 Employee 和 Project 之间的一对一关联,如下图所示。
使用 C++ 实现 WorksOn
class WorksOn { private: Employee e; Project p; Hours h; char * date; public: // class methods };
实施约束
类中的约束限制了属性可能采用的值的范围和类型。 为了实现约束,当从类实例化对象时,会为属性分配有效的默认值。 每当运行时更改该值时,都会检查该值是否有效。 无效值可以由异常处理例程或其他方法处理。
示例
考虑一个 Employee 类,其中年龄是一个属性,其值可能在 18 到 60 范围内。以下 C++ 代码合并了它 −
class Employee { private: char * name; int age; // other attributes public: Employee() { // default constructor strcpy(name, ""); age = 18; // default value } class AgeError {}; // Exception class void changeAge( int a) { // method that changes age if ( a < 18 || a > 60 ) // check for invalid condition throw AgeError(); // throw exception age = a; } };
实现状态图
有两种替代实现策略可以在状态图中实现状态。
类中的枚举
在此方法中,状态由数据成员(或数据成员集)的不同值表示。 这些值由类中的枚举显式定义。 转换由更改相关数据成员值的成员函数表示。
泛化层次结构中类的排列
在此方法中,状态以可通过公共指针变量引用的方式排列在泛化层次结构中。 下图展示了从状态图到泛化层次结构的转换。
对象映射到数据库系统
对象的持久性
开发面向对象系统的一个重要方面是数据的持久性。 通过持久性,对象的寿命比创建它的程序更长。 持久数据保存在辅助存储介质上,可以在需要时重新加载。
RDBMS 概述
数据库是相关数据的有序集合。
数据库管理系统 (DBMS) 是一个软件集合,可促进定义、创建、存储、操作、检索、共享和删除数据库中的数据的过程。
在关系数据库管理系统 (RDBMS) 中,数据存储为关系或表,其中每一列或字段代表一个属性,每一行或元组代表一个实例的记录。
每一行都由一组选定的称为主键的最小属性唯一标识。
外键是一个属性,它是相关表的主键。
将类表示为 RDBMS 中的表
要将类映射到数据库表,每个属性都表示为表中的一个字段。 将现有属性指定为主键,或者将单独的 ID 字段添加为主键。 该类可以根据需要进行水平或垂直划分。
例如,Circle类可以转换为表格,如下图所示。
Schema for Circle Table: CIRCLE(CID, X_COORD, Y_COORD, RADIUS, COLOR) Creating a Table Circle using SQL command: CREATE TABLE CIRCLE ( CID VARCHAR2(4) PRIMARY KEY, X_COORD INTEGER NOT NULL, Y_COORD INTEGER NOT NULL, Z_COORD INTEGER NOT NULL, COLOR );
将关联映射到数据库表
一对一关联
为了实现 1:1 关联,任何一个表的主键都被指定为另一个表的外键。 例如,考虑部门和经理之间的关联 −
用于创建表的 SQL 命令
CREATE TABLE DEPARTMENT ( DEPT_ID INTEGER PRIMARY KEY, DNAME VARCHAR2(30) NOT NULL, LOCATION VARCHAR2(20), EMPID INTEGER REFERENCES MANAGER ); CREATE TABLE MANAGER ( EMPID INTEGER PRIMARY KEY, ENAME VARCHAR2(50) NOT NULL, ADDRESS VARCHAR2(70), );
一对多关联
为了实现 1:N 关联,将关联 1 端的表的主键指定为关联 N 端的表的外键。 例如,考虑部门和员工之间的关联 −
用于创建表的 SQL 命令
CREATE TABLE DEPARTMENT ( DEPT_ID INTEGER PRIMARY KEY, DNAME VARCHAR2(30) NOT NULL, LOCATION VARCHAR2(20), ); CREATE TABLE EMPLOYEE ( EMPID INTEGER PRIMARY KEY, ENAME VARCHAR2(50) NOT NULL, ADDRESS VARCHAR2(70), D_ID INTEGER REFERENCES DEPARTMENT );
多对多关联
为了实现 M:N 关联,需要创建一个代表关联的新关系。 例如,考虑 Employee 和 Project &minus 之间的以下关联;
Works_On 表架构 − WORKS_ON (EMPID, PID, HOURS, START_DATE)
创建 Works_On 关联的 SQL 命令 − CREATE TABLE WORKS_ON
( EMPID INTEGER, PID INTEGER, HOURS INTEGER, START_DATE DATE, PRIMARY KEY (EMPID, PID), FOREIGN KEY (EMPID) REFERENCES EMPLOYEE, FOREIGN KEY (PID) REFERENCES PROJECT );
将继承映射到表
为了映射继承,基表的主键被指定为主键以及派生表中的外键。
示例