题
哪个类设计更好,为什么?
public class User
{
public String UserName;
public String Password;
public String FirstName;
public String LastName;
}
public class Employee : User
{
public String EmployeeId;
public String EmployeeCode;
public String DepartmentId;
}
public class Member : User
{
public String MemberId;
public String JoinDate;
public String ExpiryDate;
}
或者
public class User
{
public String UserId;
public String UserName;
public String Password;
public String FirstName;
public String LastName;
}
public class Employee
{
public User UserInfo;
public String EmployeeId;
public String EmployeeCode;
public String DepartmentId;
}
public class Member
{
public User UserInfo;
public String MemberId;
public String JoinDate;
public String ExpiryDate;
}
解决方案
通过认识到继承模型是一种“IS-A”关系,而成员资格模型是一种“HAS-A”关系,就可以简单地回答这个问题。
- 员工就是用户
- 员工有用户信息
哪一个是正确的?这就是你的答案。
其他提示
两者我都不喜欢。当某人既是会员又是雇员时会发生什么?
问自己以下问题:
- 你想为员工建模吗 是 用户?如果是这样,就选择继承。
- 你想为员工建模吗 有 用户信息?如果是这样,请使用组合。
- 用户(信息)和员工之间是否涉及虚拟功能?如果是这样,请使用继承。
- 一个 Employee 可以有多个 User (info) 实例吗?如果是这样,请使用组合。
- 将 Employee 对象分配给 User (info) 对象是否有意义?如果是这样,请使用继承。
一般来说,在代码复杂性和所需效率的约束下,努力对程序模拟的现实进行建模。
我不认为组合总是比继承更好(只是通常)。如果Employee和Member确实是Users,并且它们是互斥的,那么第一个设计会更好。考虑您需要访问员工的用户名的场景。使用第二种设计,您将拥有:
myEmployee.UserInfo.UserName
这是不好的(德墨忒耳定律),所以你可以重构为:
myEmployee.UserName
这需要 Employee 上的一个小方法来委托给 User 对象。所有这些都被第一个设计所避免。
好问题,虽然是为了避免分心 正确的 和 错误的 我会考虑询问每种方法的优缺点——我认为这就是你所说的更好或更差的意思以及原因。反正 ....
第一种方法又称继承
优点:
- 允许多态行为。
- 是 最初 简便。
缺点:
- 可能 随着时间的推移变得复杂或笨拙 如果 添加了更多的行为和关系。
第二种方法又名组合
优点:
- 很好地映射到非 oop 场景,例如关系表、结构化编程等
- 很简单(如果不一定方便) 逐渐地 扩展关系和行为。
缺点:
- 没有多态性,因此使用相关信息和行为不太方便
像这样的列表+问题 乔恩·林贾普 提到的将帮助您做出决定并开始 - 然后您可以找到 正确的 答案应该是;-)
您也可以将 Employee 视为 角色 用户(人)的。用户的角色可以随时间改变(用户可能失业)或者用户可以同时拥有多个角色。
当存在时继承要好得多 真实的 “是”关系,例如苹果 - 水果。但要非常小心:圆 - 椭圆不是真正的“是”关系,因为圆比椭圆具有更少的“自由度”(圆是一个 状态 椭圆) - 参见: 圆椭圆问题.
真正的问题是:
- 用户背后的业务规则和用户故事是什么?
- 员工背后的业务规则和用户故事是什么?
- 会员背后的业务规则和用户故事是什么?
它们可以是三个完全不相关的实体,也可以不是,这将决定您的第一个或第二个设计是否可行,或者是否需要另一个完全不同的设计。
两者都不好。太多的可变状态。您不应该能够构造处于无效或部分初始化状态的类的实例。
也就是说,第二个更好,因为它更倾向于组合而不是继承。
说明您的要求/规格可能有助于实现“最佳设计”。
目前你的问题太“取决于读者的解释”。
您应该考虑以下场景:
如果同一用户可以同时是员工和成员,则组合(第二个示例)是更好的选择。为什么?因为对于代表同一个 User 的两个实例(Employee 和 Member),如果 User 数据发生变化,您不必在两个地方更新它。只有 User 实例包含所有 User 信息,并且只有它需要更新。由于 Employee 和 Member 类都包含相同的 User 实例,因此它们将自动包含更新的信息。
另外三个选项:
有
User
类包含员工和成员的补充信息,未使用的字段为空(ID
某个特定的User
将指示用户是否是雇员、会员、两者或其他)。有一个
User
包含对的引用的类ISupplementalInfo
, , 在哪里ISupplementalInfo
继承于ISupplementalEmployeeInfo
,ISupplementalMemberInfo
, , ETC。适用于所有用户的代码可以使用User
类对象和具有User
参考可以访问用户的补充信息,但这种方法可以避免更改User
如果将来需要补充信息的不同组合。如上所述,但有
User
类包含某种集合ISupplementalInfo
. 。这种方法的优点是便于在运行时向用户添加属性(例如因为一个Member
被录用了)。当使用前一种方法时,必须为不同的属性组合定义不同的类;将“成员”转变为“成员+客户”与将“员工”转变为“员工+客户”需要不同的代码。后一种方法的缺点是,它会更难防范冗余或不一致的属性(使用类似Dictionary<Type, ISupplementalInfo>
保存补充信息是可行的,但看起来有点“笨重”)。
我倾向于第二种方法,因为它比直接继承更好地允许未来扩展。使用对象集合而不是单个对象可能会有点麻烦,但该方法可能比其他方法更好地处理不断变化的需求。