我正在构建一个需要许多具有类似属性的子类(Person)的应用程序(例如:学生,教师,联系人,用户)。属性会有相当大的重叠,但也存在很多差异。例如,一个人可以是学生,联系人和用户。以下是一个示例(仅限于清晰度):
Person
FirstName
LastName
DOB
CurrentAge
Student <- Person
StudentId
Average
Email
Phone
Contact <- Person
Email
Phone
Address
User <- Person
Email
UserName
DOB
CurrentAge
我想避免多次编写代码 - 例如:电子邮件验证代码,计算年龄所需的代码等。此外,我们可能必须稍后添加其他类,具有类似的重叠和差异。
什么被认为是处理这个的好设计,或者是什么设计模式(如果有的话)涵盖了这个?
从我对设计模式的基本理解来看,Decorator似乎不对b / c我没有添加行为。复合似乎不正确b / c它不是递归的。我也明白,可能没有理想的模式,但是,这似乎是一个非常普遍的要求。
如果重要,这将主要用于ASP.NET / C#/ VB.NET。
其他SO问题有两个相似的类/对象(通常是子类)的答案,但我找不到任意数量的类似类。
欢迎任何有关相关数据库设计的建议。
答案 0 :(得分:4)
您希望使用Composition来组合多个不同类的功能。您真正需要的是如何设计对象层次结构,以便根据需要定义不同级别的功能。最好和最简单的方法是使用Composition来定义功能。
例如,在您的示例中,Person
不需要拥有电子邮件地址;但是,Contact
可以,User
可以;他们都继承自Person
。处理此问题的方法是拥有Email
类,然后您的Contact
和User
类可以拥有该类;该课程可以管理验证等。如果您真的希望将Email
附加到Person
,那么您可以拥有PersonWithEmail
课程(请选择更好的名字!)继承自Person
,并将继承的Person
与Email
类组合在一起;这样,任何继承自PersonWithEmail
的类都将获得Person
功能和Email
功能。但是,这种方法的问题在于您直接在继承层次结构中定义组合;这可能不是所希望的。直接组合方法更简单。
答案 1 :(得分:0)
您可以在Person
类中存储所有不同属性的存储,并为可以访问属性的不同类型的人员创建子类。这样,学生和联系人的Phone
属性可以具有相同的存储空间。
您可以拥有子类型的标志,以及将人物作为子类型的属性。
示例:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public string DOB { get; set; }
public int CurrentAge { get; set; }
private string _studentId;
private double _average;
private string _email;
private string _phone;
public bool IsStudent { get; private set; }
public Student AsStudent {
get {
if (IsStudent) {
return this as Student;
} else {
throw new Exception("This Person is not Student.");
}
}
}
}
public class Student : Person {
public string StudentId { get { return _studentId; } set { _studentId = value; } }
public double Average { get { return _average; } set { _average = value; } }
public string Email { get { return _email; } set { _email = value; } }
public string Phone { get { return _phone; } set { _phone = value; } }
}
用法:
Person someone = GetStudentSomehow(...);
Console.WriteLine(someone.FirstName);
Console.WriteLine(someone.AsStudent.Phone);
答案 2 :(得分:0)
我会反对使用子类化,原因有两个:
将实际识别某人的内容放在Person
课程中。
将与人正在玩的角色有关的所有内容分成一个单独的类或接口,可能是Role
,并创建其子类或实现。
通过在Person
类中添加一个包含Set
个Role
对象的字段,允许某人拥有多个角色。
答案 3 :(得分:0)
如果您可以说类是跟随关系,则使用子类化Tiger“是”Animal,否则可能是一个混乱的维护如此大的类层次结构添加新行为。
另外,不要忘记将基类设为abstract
,当有人打算使用基类作为实例,基类应设计为基类时,它会阻止在功能中使用类的错误,这就是它
对于某种类型的属性,我建议使用这种方法而不是基类,它们为不同类型的实体共享相同的属性,因此通过接口封装这些属性,并只为了解联系信息细节的实体实现:
public interface IContactDetails
{
string Email { get; }
string Address { get; }
}