如何以面向对象的思想设计存在关联的实体类?
针对前两天在本人公司引起同事激烈讨论的话题(如何以面向对象的思想设计存在关联的实体类),我设想了一个虚拟的应用场景,通过翻阅各种资料、请教各位同事以及结合我自己的一些经验,进行了简单的设计。这种设计是我自认为合理,并极力鼓吹加以应用的一种设计方法。欢迎各位高人猛烈抨击,不吝指教,指出设计缺陷,以求大家共同进步!
补充:
针对各位网友的评论,我把我当时遇到的问题也贴出来,让大家来议论一下,怎么做才是真正的面向对象。
我的问题疑问点:当两个实体类是“has”关系时,该如何设计这两个类?
1、班级类中有List<学生类>属性,学生类中有班级类属性;
2、班级类中有List<学生类>属性,学生类中没有任何关于班级的属性;
3、两个类中都没有任何对方的属性,它们的关系体现在业务类中;
4、班级类中没有List<学生类>属性,学生类中有标明班级的唯一标示的、类型是基本类型的属性
以上是我们形成的四种不同的观点,那哪一种是面向对象的呢?
我个人认为
第1种会造成嵌套;
第2种把List<学生类>当成一个属性,是否会使这个类变的庞大?如果不是班级,而是仓库和仓库里上万种的物料呢。岂不是List里有上万笔记录,在不需要的时候,不占内存吗?
第3种看起来好像很符合面向对象,但在处理诸如已知一个学生,然后得到他对应的班级中的全部学生时有点麻烦;
第4中就是我现在想出来的方法,但大家都说这个不符合面向对象,那到底应该怎么做呢?
以下就是我目前想出来的方案:
假设需求:设计一个学生管理系统,实现如果发现某班级中的一位同学犯错误,则全班同学每个人都扣除一个小红花;
1、 设计实体类;如图:
2、 映射数据表;
略
3、 设计客户端
a) 由需求得知这里需要一个公开的惩罚方法:Punish(blunderStudent : Student);
b) 由需求得知实现惩罚方法的算法:
i. 通过某个学生得到该学生所在的班级:GetClass(classId : Integer) : Class
ii. 通过班级得到该班的全部学生: GetStudentList(classId : Integer) : List<Student>
iii. 循环所有学生,扣除每个人一个小红花:SubFlower(blunderStudent : Student)
4、 设计业务类
a) 业务中有两个方法需要学生业务类去实现:GetClass(classId : Integer) : Class、SubFlower(blunderStudent : Student);
b) 业务中有一个方法需要班级业务类去实现:GetStudentList(classId : Integer) : List<Student>
5、 设计持久层接口
a) 学生业务类中的GetClass(classId : Integer) : Class方法需要通过持久层获取对象;SubFlower(blunderStudent : Student)方法需要通过持久层保存对象;
b) 班级业务类中的GetStudentList(classId : Integer) : List<Student>方法需要通过持久层获取对象列
6、 设计持久层
a) 分别实现持久层接口
7、 通过ORM工具实现持久层与数据表的关联
略
8、 根据不同的部署环境,选择设计Web UI或WinForm UI,或其他用户界面
略
附:整个类图
我做了以下改动:
1、将减少小红花的行为,重新放回到学生实体类中。依据是:“自己的事情自己做”
2、删除原来客户端业务类中的不必要的私有方法,变成了只封装“惩罚学生”的公共方法的业务类
3、原来的StundetnController和ClassController类其实是服务类,故变成一个统一的服务类,这个服务类本质是提供持久层操作服务的,故设计了根据班级ID查找学生队列,以及保存学生最新状况的方法,而这个服务类是依赖于IDao接口的。
4、设计持久层接口,提供根据自身ID查找子类列以及更新对象的泛型方法;
5、设计持久层泛型类,处理实体类的CURD操作;
以下是新的类图,欢迎继续拍砖!