开发者

What is considered good design for multiple similar classes

I am building an application that requires a number of subclasses (of Person) with similar properties (ex: Student, Teacher, Contact, User). There will be considerable overlap in properties, but also many differences. For example, a Person could be a Student, Contact and User. Here is an example (limited for clarity):

Person
  FirstName
  LastName
  DOB
  CurrentAge

Student <- Person
  StudentId
  Average
  Email
  Phone

Contact <- Person
  Email
  Phone
  Address

User <- Person
  Email
  UserName
  DOB
  CurrentAge

I would like to avoid writing code multiple times - ex: email validation code, the code required to calculate Age, etc. Also, we will probably have to add additional classes later with similar overlapp and differences.

What is considered good design for handling this, or what design pattern(s), if any, cover this?

From my basic understanding of design patterns, Decorator does not seem right b/c I am not adding behavior. Composite does not seem right b/c it is not recursive. I also understand that there may not be an ideal pattern for this, however, it seems like a very common requirement.

If it matters, this will mainly be used in ASP.NET/C#/VB.NET.

Other SO questions have answers for two similar classes/objects (generally subclassing) but I could not find anything for an arbitrary number of similar classes.

Any suggestions regarding the associ开发者_StackOverflow社区ated database design are also welcome.


You want to use Composition to combine the functionality of multiple differing classes. What you're really looking for is how to design your object hierarchy such that you can define varying levels of functionality based upon your needs. The best and simplest way to do this is to use Composition to be able to define functionality.

For example, in your example, a Person does not need to have an email address; however, a Contact does, and a User does; they both inherit from Person. The way to handle this is to have an Email class, which then your Contact and User classes can have; that class can manage the validation, etc. If you really wish to have your Email attached to a Person, you can have a PersonWithEmail class (choose a better name, please!) which inherits from Person, and which composes the inherited Person with the Email class; that way, any class which inherits from PersonWithEmail will gain the Person functionality and the Email functionality. The issues with this type of approach, however, are that you're defining your composition directly in your inheritance hierarchy; this may not be desired. The direct Composition approach is simpler.


You could have storage in the Person class for all the different properties, and have subclasses for the different types of persons where the properties are reachable. That way the Phone property for a student and a contact could have the same storage.

You can have flags for the subtypes, and properties to get a person as the subtype.

Example:

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; } }
}

Usage:

Person someone = GetStudentSomehow(...);
Console.WriteLine(someone.FirstName);
Console.WriteLine(someone.AsStudent.Phone);


I would argue against using subclassing for this at all, for two reasons:

  • A person can sensibly be a student, a contact and a user simultaneously.
  • A person can be a student now and a teacher next year (and for grad students, both at once...)

Put the things that actually identify a person in a Person class. Separate everything that has to do with a role that person is playing into a separate class or interface, possibly Role, and create subclasses or implementations of that.

Allow a person to have multiple roles by putting a field in your Person class that is a Set containing Role objects.


Use subclassing in case if you can say that classes are follow relation Tiger "is an" Animal, otherwise it could be a mess maintaining such a large hierarchy of classes adding a new behaviour.

Also, do not forget to make a base class as abstract, it prevent incorrect usage of classes in feature when someone intended to use base class as instance, base class should be designed to be a base, and thats it.

For some kind of properties iI would propose to use such an approach instead of base classes which share the same properties for different kind of entities, so encapsulate such properties by an interface and just implement for entities which are aware of contact information details:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜