什么被认为是多个类似类的好设计

时间:2011-07-11 17:37:28

标签: .net design-patterns class-design

我正在构建一个需要许多具有类似属性的子类(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问题有两个相似的类/对象(通常是子类)的答案,但我找不到任意数量的类似类。

欢迎任何有关相关数据库设计的建议。

4 个答案:

答案 0 :(得分:4)

您希望使用Composition来组合多个不同类的功能。您真正需要的是如何设计对象层次结构,以便根据需要定义不同级别的功能。最好和最简单的方法是使用Composition来定义功能。

例如,在您的示例中,Person不需要拥有电子邮件地址;但是,Contact可以,User可以;他们都继承自Person。处理此问题的方法是拥有Email类,然后您的ContactUser类可以拥有该类;该课程可以管理验证等。如果您真的希望将Email附加到Person,那么您可以拥有PersonWithEmail课程(请选择更好的名字!)继承自Person,并将继承的PersonEmail类组合在一起;这样,任何继承自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类中添加一个包含SetRole对象的字段,允许某人拥有多个角色。

答案 3 :(得分:0)

如果您可以说类是跟随关系,则使用子类化Tiger“”Animal,否则可能是一个混乱的维护如此大的类层次结构添加新行为。

另外,不要忘记将基类设为abstract,当有人打算使用基类作为实例,基类应设计为基类时,它会阻止在功能中使用类的错误,这就是它

对于某种类型的属性,我建议使用这种方法而不是基类,它们为不同类型的实体共享相同的属性,因此通过接口封装这些属性,并只为了解联系信息细节的实体实现:

public interface IContactDetails
{
    string Email { get; }
    string Address { get; }
}