c# - 在基类中声明子类;坏不坏?

标签 c# oop object-oriented-analysis

最近我发现一些代码将子类型声明为基类中的枚举。这是一个简单的例子:

public enum EmployeeType
{
    Manager,
    Secretary
}

public class Employee
{
    public string Code { get; set; }

    public EmployeeType Type { get; set; }
}

public class Manager : Employee
{
    public void Manage()
    {
        // Managing
    }
}

public class Secretary : Employee
{
    public void SetMeeting()
    {
        // Setting meeting
    }
}

根据我的开发经验,我写了an article关于它,宣布这是一种不好的做法/设计。我认为这很糟糕,因为基类应该对其子类不可知。它应该没有关于其子类的信息,这里至少有两个原因:

  1. 可扩展性:此设计将不可扩展,因为如果您想定义另一个派生类,例如 Developer,您还应该更新 EmployeeType 枚举,您可能无权访问的内容。
  2. 矛盾的定义:现在你可以写出这段代码:

    Secretary secretary = new Secretary();
    secretary.EmployeeType = EmployeeType.Manager;
    /*
    This is absurd semantically. But syntactically, it's possible.
    */
    

然而,当我读到Wikipedia's article about inheritance , 我找不到我的问题的任何答案。

虽然乍一看可能有争议,但我相信继承应该足够成熟,可以为这个难题提供可靠的答案。这段代码不好吗,smelly code ?还是可以接受和合理的?为什么?

最佳答案

我认为当我们回到何时使用继承的哲学时,问题就可以解决。
据说“将继承视为是一种关系

当您在两个类之间建立继承关系时,您可以利用动态绑定(bind)和多态性。
动态绑定(bind) 是指在运行时调用哪个方法实现,基于对象的类。
多态性 意味着您可以使用父类(super class)类型的变量来保存对其类是父类(super class)或其任何子类的对象的引用。

动态绑定(bind)和多态性的主要好处之一是它们可以帮助使代码更容易更改。如果您有一段代码使用父类(super class)类型的变量,例如 Employee,您可以稍后创建一个全新的子类,例如 Manager,并且旧代码片段将在新子类的实例中不做任何更改。如果 Manager 覆盖代码片段调用的任何 Employee 方法,动态绑定(bind)将确保 Managers 对这些方法的实现得到执行。即使在编写和编译代码片段时类管理器不存在,也是如此。

现在回到问题,为什么我们需要 Employee 中的 EmployeeType?
可能有一些我们想在 Employee 中实现的功能,也就是 CalculateSalary()

CalculateSalary(){
if (EmployeeType == EmployeeType.Manager) // Add management percent }

理由很诱人,但如果员工既是经理又是主管怎么办?
它会很复杂!我们可以简单地将 CalculateSalary() 实现为抽象方法,但我们会失去目标!
Coad 规则来了:
子类表示是一种特殊的并且不是a所扮演的角色
Liskov Substitution原则是对“我应该从这种类型继承吗?”的测试

以上拇指的作用是:

  • TypeB 是否要公开完整的接口(interface)(所有公共(public)方法 不少于)TypeA 使得 TypeB 可以在 TypeA 所在的地方使用 预期的?表示继承。
    例如塞斯纳双翼飞机将暴露 飞机的完整界面,如果不是更多的话。所以这使得它 适合从飞机派生。
  • TypeB 是否只想要 TypeA 公开的部分/部分行为? 表示需要组合。
    例如一只鸟可能只需要苍蝇 飞机的行为。在这种情况下,提取它是有意义的 out 作为接口(interface)/类/两者并使其成为两者的成员 类(class)。

作为脚注来自 javaworld :
确保继承对 is-a 关系建模。
不要仅仅为了代码重用而使用继承。
不要仅仅为了多态而使用继承。
优先考虑组合而不是继承。

我觉得在这种场景下,管理者是员工扮演的角色,这个角色可能会随着时间的推移而改变,这个角色会作为一个组合来实现。

作为域模型中 View 的另一个方面,并将其映射到关系数据库。将继承映射到 SQL 模型真的很难(您最终会创建并不总是使用的列,使用 View 等)。一些 ORM 试图处理这个问题,但它总是很快变得复杂。
例如 Hibernate 的 One Table Per Class Hierarchy 方法,违反了 2NF并且很可能导致您的样本不一致

Secretary secretary = new Secretary();
secretary.EmployeeType = EmployeeType.Manager;

关于c# - 在基类中声明子类;坏不坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20018266/

相关文章:

c# - 如何叠加两个图像(作为字节数组)

c# - 实例化和接口(interface)

java android View 结构

c# - Xamarin IOS UITableViewController RowSelected 导航到 UIViewController

c# - 如何使用 visual c# 从 access mdb 获取数据并将其放入 postgresql 表中?

java - 在 OO 中设计某些东西时

java - JPanel 面向对象图形

java - 利用 try catch block 而不是重复进行空检查

C# Excel 单元格内容部分删除

java - 为什么不直接为所有对象声明 Object 类呢?