1

首先抱歉我的英语不好 :D 最近由于软件工程考试,我正在更深入地学习设计模式,我必须设计一个软件系统作为这次考试的项目。

有一个我无法处理的问题:如何将实体类(代表我的应用程序域的数据)与……其他一切分离!

我的意思是,更具体地说,如果我有一个类 Patient(具有自己的私有属性和公共 getter 和 setter 方法),这是一个实体类,我认为到目前为止我做对了:D

所以假设我选择使用 MVC 模式架构来设计我的程序,Patient 类将在 Model 中,对吗?

现在,每个处理该类的视图都会引用它:假设我有三个视图:第一个视图查看所有患者,另一个用于修改患者,最后一个用于注册新患者(实际上还有其他课程我应该提交一些报告,但我认为现在这无关紧要)。

这些类中的每一个都将知道 Patient 的结构以显示其数据,例如,它们将调用其 getter 方法并以某种方式显示数据。

我认为没有办法避免这种情况,因为视图在语义上与它必须显示的数据(=模型)相关联:我的意思是它必须知道数据是字符串、日期还是整数,并且它还必须知道它的语义(它在现实世界中代表什么);所以我认为仅仅删除对 Patient 类的引用没有多大意义。

现在问题的核心是:如何防止 Patient 类中的更改传播到使用它的所有类(不仅仅是视图)?

我的意思是:假设 String[] Cellular 中的属性 String Cellular 发生了变化,因为需求发生了变化。我将不得不修改:1)数据库/数据库接口 2)患者类 3)(最糟糕的是)每个使用患者的类!

如何避免这种情况?我认为在一个好的项目中,单个类的更改不应传播到使用该类的所有模块的更改链中,但我是初学者,我想不出一种方法来防止这种情况发生。

我什至想不出一种为实体类使用稳定接口的好方法,因为需求的变化会反映接口的变化(而且我不认为接口应该被改变!)。

请帮忙!!

4

4 回答 4

1

想到的第一个评论是,您说您必须更改一堆使用该 Cellular 属性的类,就像这是一件坏事。

这实际上是强类型语言的特性之一。它确保类型在使用该属性的整个系统中保持一致。

例如,如果 Cellular 字段从 String 更改为 String[],当然您的 DB 模型也应该调整以反映从 1-1 关系到 1-many 关系的变化,因此您的数据访问对象(或 ORM层配置)需要调整以反映变化。编译器不会让您侥幸逃脱,这是一件好事。

另一个评论是,只有使用 Cellular 字段的类才需要调整。但在这里,这是一件好事。因此,如果您有一个收集患者手机号码的用户界面,现在编译器会告诉您您应该真正允许用户收集多个号码。

在设计软件时,花大量时间使模型尽可能正确是至关重要的。并且知道需求会在一定程度上发生变化,不要害怕重构也至关重要。Eclipse、NetBeans 或 IntelliJ 等现代 IDE 可以代表您协助并完成大部分繁忙的重构工作。

于 2012-07-31T18:30:15.273 回答
0

并非所有更改都可以隔离到模型或视图或持久层。但是在您的情况下,您可以使 Patient 模型具有通用的联系字段列表。该视图获取它们的列表并为用户填充一些可编辑的文本框。DatabaseMapper 通常也保留这些字段。

因此,除非 GUI 需要更大幅度地更改,否则可以纯粹在模型中添加 Cellular。除非你知道你需要,否则你不会开始一般地构建它,但你可以重构它。

于 2012-07-31T18:38:40.487 回答
0

对于您的实体类,我认为您应该将接口抽象留在最后,在您定义了所有业务实体并可以推断出它们之间的共同行为模式之后。只有这样你才能推断出它们之间的共同接口。但是您的实体类最终是具体的;试图进一步抽象它们是没有意义的。

最终,对这些具体类的更改将需要更改与它们交互的控制器/视图。不要为此烦恼。一旦您为每个实体定义了所有视图,您就可以开始制定抽象(如果有的话)。

如果您已经定义了具体实体,那么您可以开始抽象化视图。举个金融例子,假设我有一个贸易课程。显然我可以有特定类型的交易,比如 BondTrade、EquityTrade 等。所以我也可以有一个 TradeView,它可以有具体的视图,即 BondTradeView、EquityTradeView 等。你可以有更高层次的抽象,但最终,您将需要定义特定视图的具体类。

以外观设计模式为例。外观可用于根据您的具体实现创建视图。这是一种统一所有具体实体的方式。它将包含基于您的实体知道要创建什么视图以及如何创建视图的逻辑。这将是一种简化对实体进行的传播更改的方法。

于 2012-07-31T18:40:27.703 回答
0

好的,下面的语句:

这些类中的每一个都将知道 Patient 的结构以显示其数据,例如,它们将调用其 getter 方法并以某种方式显示数据。

只是半真半假。您的视图不应该知道 aPatient是什么。它可能有一些称为PatientView它运行的模型的东西。因此,位于模型和视图之间的部分需要执行突变。基本上看起来像这样:

public PatientView convertPatient(Patient patient)  
{  
    return new PatientView(patient.foo(),patient.bar(),etc);  
} 

函数的契约保证一个PatientView对象被返回给调用者,随后这个类是封装它的类定义的接口的一部分。这也具有视图不知道 aPatient是什么的优点。

底层模型的任何变化,即驱动整个应用程序的东西,当然会导致某种类型的连锁反应。转换器的使用有助于最大限度地减少接触点,因为您的应用程序的任何部分都不应该真正知道 aPatient是什么,并且每个区域之间应该有一个连接器:视图、控制器等,将患者转换为该部分的预期内容应用程序。

于 2012-07-31T18:40:57.130 回答