【问题标题】:Multiple Inheritance Substitute in C# - Specific Hypothetical Example With Logic in The PropertiesC# 中的多重继承替换 - 属性中带有逻辑的特定假设示例
【发布时间】:2019-07-07 15:23:17
【问题描述】:

假设有 2 个类具有相同的属性,并且该属性中也包含逻辑。

public class Manager
{
    private string _ssn { get; set; }

    [RegularExpression(@"\d{9}")]
    public string SSN
    {
        get
        {
            return _ssn;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
                _ssn = someLogicalMethod (value);
        }     
    }
}

还有

public class Employee
{
    private string _ssn { get; set; }

    [RegularExpression(@"\d{9}")]
    public string SSN
    {
        get
        {
            return _ssn;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
                _ssn = someLogicalMethod(value);
        }     
    }
}

理想情况下,您应该创建一个抽象基类 (BaseSSN),它们将从中继承。这一切都很好,但并不理想!这样做的原因是因为在 C# 中您只能从 1 个超类继承。这意味着,如果您的经理和员工都有 SSN,但经理和新类 (CEO) 具有 ManagerOf 属性,那么您必须创建一个实现 BaseSSN 类的新类,但它也将是一个抽象类 (BaseManagerOf),其中包含 Managerof 的逻辑。然后,Manager 和 CEO 将从新类继承。但是,如果某人是经理但自己没有 SSN,现在您将不得不创建另一个类。您需要拉出 Manager 属性并将其放在一个 super 中,以将其与 SSN 类分开。

你知道我要做什么了吗?它可以根据每个类拥有的与其他类相似的道具数量创建 N 种变体。

所以我想做的只是

公共类管理器:BaseSSN、BaseManagerOf、X

X 是什么。你可以用接口做到这一点,但接口不能包含逻辑。

我相信可能有一个平稳的策略可以解决这个问题,但我一辈子都想不通。

编辑:

我的问题似乎有点混乱:这是一个假设性问题。我明白经理是雇员。一个简单的问题是我希望一个类实现 2 个抽象并且不能在 C# 中做到这一点。但是,是否有一种策略可以让它以任何方式发挥作用?

public class Manager : BaseManager
{
}

public abstract class BaseManager : BaseSSN
{

    private string _managerOf;
    public int ManagerOf
    { 
         get
         {
             return _managerOf;
         }
         set
         {
             if (!string.IsNullOrEmpty(value))
                 _managerOf = someLogicalMethod(value);
         }     
     }
}

public abstract class BaseSSN
{
    private string _ssn { get; set; }

    [RegularExpression(@"\d{9}")]
    public string SSN
    {
        get
        {
            return _ssn;
        }
        set
        {
            if (!string.IsNullOrEmpty(value))
                _ssn = someLogicalMethod(value);
        }     
    }
}

public class CEO : ManagerOf {}

现在它开始与 CEO 分道扬镳。我不想要 CEO 的 SSN,只想要他管理的人。因此,我必须将逻辑从继承 SSN 的 ManagerOf 类中提取出来,并将其放入自己的类中。那么 CEO 就没有 SSN 属性了。但是,现在我不能在我的 Manager 类中同时拥有 ManagerOf 逻辑和 SSN 逻辑,而无需创建另一个类似于以下类的抽象......

public class ManagerOfAndSSN: SSN
{
    // repetitive manager logic here
}

【问题讨论】:

  • 你为什么要只拆分 SSN 并从中继承?这真的没有意义......员工不是SSN......
  • 如果有人将该 SSN 属性设置为 null 或空字符串 (thing.SSN = someAccidentallyEmptyString;),会发生什么情况。悄悄地忽略这样的动作是解决间歇性问题的好方法,没有人能够追踪到。一个解决方案(针对您的问题)是使 SSN 成为一个自己的类(能够解释多种输入格式(除了匹配 @"\d{9}" 的正则表达式,能够以多种方式格式化自身(包括“最后 4 个”)。然后你让它做你的设置器逻辑
  • 为什么经理不是员工的一种?我认识的每个经理都是员工。
  • 显然“具有默认实现的接口”被提议作为 C# 8 的一项功能,这将解决您的问题。 Java 已经有这个特性了,还是蛮好用的。
  • “假设性问题”是否意味着您实际上并不想要答案?

标签: c# object inheritance interface abstract


【解决方案1】:

一个答案是使用接口和组合。实现功能的“基”类(例如ManagerOfSSN)实现接口,然后将它们作为依赖项提供给需要它们的类:

public interface ISsn
{
    string Ssn { get; set; }
}
public interface IManagerOf
{
    List<Employee> Manages { get; set; }
}

public class Ssn : ISsn { ... }
public class ManagerOf : IManagerOf { ... }

现在您可以将这些类注入到将它们组合在一起的类中:

// here we are implementing the interfaces on the class
public class Employee : ISsn
{
    private ISsn _ssn;

    public Employee(ISsn ssn)
    {
        _ssn = ssn;
    }

    public string Ssn
    {
        get { return _ssn.Ssn; }
        set { _ssn.Ssn = value }
    }
}

public class Manager : ISsn, IManagerOf
{
    private ISsn _ssn;
    private IManagerOf _managerOf;

    public Employee(ISsn ssn, IManagerOf managerOf)
    {
        _ssn = ssn;
        _managerOf = managerOf;
    }

    public string Ssn
    {
        get { return _ssn.Ssn; }
        set { _ssn.Ssn = value }
    }

    public List<Employee> Manages
    {
        get { return _managerOf.Manages; }
        set { _managerOf.Manages = value; }
    }
}

或者,类的替代实现:

// here we're just going to expose each dependency as the interface
public class Employee : ISsn
{
    private ISsn _ssn;

    public Employee(ISsn ssn)
    {
        _ssn = ssn;
    }

    public ISsn Ssn => _ssn;
}

public class Manager2
{
    private ISsn _ssn;
    private IManagerOf _managerOf;

    public Employee(ISsn ssn, IManagerOf managerOf)
    {
        _ssn = ssn;
        _managerOf = managerOf;
    }

    public ISsn Ssn => _ssn;
    public IManagerOf ManagerOf => _managerOf;
}

这是一个相当简单的实现,在这种情况下,我会选择在每个支持该功能的类中简单地实现接口。但是,如果您对属性有更复杂的逻辑,那么组合路由会更有意义,因为那时您正在共享实现。它并不像多重继承起初看起来那样“优雅”,但请参阅Why is Multiple Inheritance not allowed in Java or C#?,了解为什么人们通常认为多重继承带来的麻烦多于解决的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 2022-07-27
    • 2013-03-31
    • 2011-03-02
    相关资源
    最近更新 更多