面向对象的最佳实践 - 继承 v 组合 v 接口 [英] Object Oriented Best Practices - Inheritance v Composition v Interfaces

查看:27
本文介绍了面向对象的最佳实践 - 继承 v 组合 v 接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想问一个关于您将如何处理一个简单的面向对象设计问题的问题.对于处理这种情况的最佳方法,我有自己的一些想法,但我很想听听 Stack Overflow 社区的一些意见.相关在线文章的链接也值得赞赏.我使用的是 C#,但问题不是特定于语言的.

I want to ask a question about how you would approach a simple object-oriented design problem. I have a few ideas of my own about what the best way of tackling this scenario, but I would be interested in hearing some opinions from the Stack Overflow community. Links to relevant online articles are also appreciated. I'm using C#, but the question is not language specific.

假设我正在编写一个视频商店应用程序,它的数据库有一个 Person 表,带有 PersonIdNameDateOfBirthAddress 字段.它还有一个 Staff 表,它有一个指向 PersonId 的链接,以及一个 Customer 表,它也链接到 PersonId.

Suppose I am writing a video store application whose database has a Person table, with PersonId, Name, DateOfBirth and Address fields. It also has a Staff table, which has a link to a PersonId, and a Customer table which also links to PersonId.

一个简单的面向对象方法是说Customer是"Person,因此创建类有点像这样:

A simple object oriented approach would be to say that a Customer "is a" Person and therefore create classes a bit like this:

class Person {
    public int PersonId { get; set; }
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Address { get; set; }
}

class Customer : Person {
    public int CustomerId { get; set; }
    public DateTime JoinedDate { get; set; }
}

class Staff : Person {
    public int StaffId { get; set; }
    public string JobTitle { get; set; }
}

现在我们可以编写一个函数来向所有客户发送电子邮件:

Now we can write a function say to send emails to all customers:

static void SendEmailToCustomers(IEnumerable<Person> everyone) { 
    foreach(Person p in everyone)
        if(p is Customer)
            SendEmail(p);
}

这个系统运行良好,直到我们有一个既是客户又是员工的人.假设我们真的不希望我们的 everyone 列表出现两次相同的人,一次是 Customer,一次是 Staff,我们是否可以任意选择:

This system works fine until we have someone who is both a customer and a member of staff. Assuming that we don't really want our everyone list to have the same person in twice, once as a Customer and once as a Staff, do we make an arbitrary choice between:

class StaffCustomer : Customer { ...

class StaffCustomer : Staff { ...

显然只有这两个中的第一个不会破坏 SendEmailToCustomers 功能.

Obviously only the first of these two would not break the SendEmailToCustomers function.

那你会怎么做?

  • Person 类具有对 StaffDetailsCustomerDetails 类的可选引用?
  • 创建一个包含 Person 以及可选的 StaffDetailsCustomerDetails 的新类?
  • 让一切都成为一个接口(例如 IPersonIStaffICustomer)并创建三个实现适当接口的类?
  • 采取另一种完全不同的方法?
  • Make the Person class have optional references to a StaffDetails and CustomerDetails class?
  • Create a new class that contained a Person, plus optional StaffDetails and CustomerDetails?
  • Make everything an interface (e.g. IPerson, IStaff, ICustomer) and create three classes that implemented the appropriate interfaces?
  • Take another completely different approach?

推荐答案

Mark,这是一个有趣的问题.你会发现很多关于这个的意见.我不相信有一个正确"的答案.这是一个很好的例子,说明在构建系统后,严格的分层对象设计确实会导致问题.

Mark, This is an interesting question. You will find as many opinions on this. I don't believe there is a 'right' answer. This is a great example of where a rigid heirarchial object design can really cause problems after a system is built.

例如,假设您选择了Customer"和Staff"类.您部署了系统,一切都很顺利.几周后,有人指出他们既是员工"又是客户",他们没有收到客户的电子邮件.在这种情况下,您需要进行大量代码更改(重新设计,而不是重构).

For example, lets say you went with the "Customer" and "Staff" classes. You deploy your system and everything is happy. A few weeks later, someone points out that they are both 'on staff' and a 'customer' and they are not getting customer emails. In this case, you have a lot of code changes to make (re-design, not re-factor).

我相信,如果您试图拥有一组实现人员及其角色的所有排列和组合的派生类,那将过于复杂且难以维护.鉴于上述示例非常简单,这一点尤其正确 - 在大多数实际应用中,事情会更加复杂.

I believe it would be overly complex and difficult to maintain if you attempt to have a set of derived classes that implement all the permutations and combination of people and their roles. This is especially true given that the above example is very simple - in most real applications, things will be more complex.

对于这里的示例,我会选择采取另一种完全不同的方法".我将实现 Person 类并在其中包含角色"的集合.每个人都可以有一个或多个角色,例如客户"、员工"和供应商".

For your example here, I would go with "Take another completely different approach". I would implement the Person class and include in it a collection of "roles". Each person could have one or more roles such as "Customer", "Staff", and "Vendor".

这样可以在发现新需求时更轻松地添加角色.例如,您可能只拥有一个基本的角色"类,并从中派生出新的角色.

This will make it easier to add roles as new requirements are discovered. For example, you may simply have a base "Role" class, and derive new roles from them.

这篇关于面向对象的最佳实践 - 继承 v 组合 v 接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆