【问题标题】:Multiple Inheritance?多重继承?
【发布时间】:2012-03-07 13:56:18
【问题描述】:

我在网上查找了可以帮助我解决令我困惑的设计问题的信息。我对复杂的继承情况不熟悉,所以我的解决方案实际上可以植根于更好的设计。但在试图弄清楚我的设计应该是什么时,我一直认为我真的只需要继承多个基类。

我的具体案例涉及资产和不同类型的资产。

从资产开始...

每个PhysicalDevice都是资产
每个 VirtualDevice 都是一个资产
每个服务器都是资产

每个 PhysicalServer 都需要同时是 PhysicalDevice 和 Server
每个 VirtualServer 都需要是 VirtualDevice 和 Server
每一个NetDevice都是一个PhysicalDevice
每个 StorageArray 都是一个 PhysicalDevice

我想一个解决方案是为 PhysicalServers 和 VirtualServers 复制 Server 代码,但是,我觉得这与我的想法背道而驰努力去做,也就是继承。

它们需要是单独的类,因为每种类型都有属性和方法。例如,Server 会有 OSCaption、Memory、Procs 等。PhysicalDevice 会有 Location、Serial、Vendor 等。而 VirtualDevice 会有有 ParentDevice、State、VHDLocation 等。

如果继承是线性的,那么我会遇到无法准确描述这些类型的问题。

似乎很有趣的是接口。看来我可以将所有基类定义为接口,并根据需要在我的主类中实现它们。但是,我只是不确定如果我这样做会产生什么影响。

例如,类似... PhysicalServer : IAsset : IServer : IPhysical

我在深水中,所以我真的只是在寻找建议或指导。

【问题讨论】:

  • 请不要在标题末尾添加“C#”。这就是标签的用途。

标签: c# class inheritance interface multiple-inheritance


【解决方案1】:

接口是确保跨类型合同完整性的适当方式,但您最终可能会为每个实现提供重复的代码。

您的方案可能比继承(或其组合)更适合组合。

示例 - 继承 + 组合

public class PhysicalServer : Asset
{
    public PhysicalInfo PhysicalProperties
    {
         get;
         set;
    }
}

public class VirtualServer : Asset
{
    public VirtualInfo VirtualProperties
    {
         get;
         set;
    }
}

示例 - 仅作曲

public class VirtualServer
{
    public VirtualInfo VirtualProperties
    {
         get;
         set;
    }

    public AssetInfo AssetProperties
    {
         get;
         set;
    }
}

然后您可以将多态性/泛型添加到组合中,并创建类型的派生来代表更具体的需求。

示例 - 继承 + 组合 + 从通用类型继承的泛化成员

public class VirtualServer<TVirtualInfo> : Asset
   where TVirtualInfo : VirtualDeviceInfo
{
    public TVirtualInfo VirtualProperties
    {
         get;
         set;
    }
}

public class VirtualServerInfo : VirtualDeviceInfo
{
   // properties which are specific to virtual servers, not just devices
}

您可以通过无数种方式对此进行建模,但借助接口、组合、继承和泛型,您可以提出有效的数据模型。

【讨论】:

  • +1 组合优于继承 - 我发现大多数情况下,继承导致一些令人头疼的问题都可以通过组合方法解决。
  • 明确地说,使用类上的接口来定义它们的作用。然后由可以完成接口所需工作的私有成员组成它们。是吗?
  • @MStodd - 是的,如果对象共享相同的合约(成员和操作),则可以(并且通常应该)在接口中定义该合约。然后也可以将不同的类型转换为相同的接口并统一处理。
  • 这需要一些研究才能弄清楚这到底意味着什么,但我想我基本上明白了。 Compisition 与 HAS-A 而不是 IS-A 关系有关?
  • @jwrightmail - 正确。我知道这是需要处理的大量信息。我建议 1) 画出你的基本对象并确定共性 2) 尝试接口和泛型 3) 阅读常见的设计模式。
【解决方案2】:

C# 不支持类的多重继承(但支持接口的多重实现)。

您要求的不是多重继承。多重继承是指一个类有多个基类。在您的示例中,每个类都继承自一个/零个其他类。 Asset 和 Server 是最终的基类。所以你在 c# 中这样做没有问题,你可以定义例如 server 中常见的功能,然后在 VirtualDevice 和 PhysicalDevice 中做不同的事情.

但是,您最终会得到一个可能很复杂的类层次结构,并且许多人会主张 组合 而不是 继承。在这里,您将拥有定义行为的接口,并且类实现该接口以表示它们执行某些操作,但是每个类可以以不同的方式实现接口方法。因此,您的 PhysicalServer 接口示例可能会受到鼓励。

【讨论】:

  • 我想澄清一下Server继承自Asset。我不确定这是否使它们都成为“终极基类”。区别很重要,因为我不仅要处理服务器,还要处理所有不同类型的虚拟和物理类型的资产。这包括服务器,是的,还包括 AttachedStorage、NetworkThing 类型等……最后,我希望能够拥有必要的基类,以基本上允许对可能出现的任何新资产类型进行可扩展性。
  • 那么只有 Asset 是最终的基类,并且正如建议的那样,通常应该首选组合并在适当的情况下进行有限继承
【解决方案3】:

首先要记住,继承是您提到的那种问题的明显结果。每个班级确实有不止一种行为,每个人都陷入了这个陷阱。好冷。你不是第一个也不是最后一个。

你需要稍微改变一下你的想法以摆脱常规。

你需要从未来“变化”的角度来看待它,而不是看一种分层的类图。类图可能不是分层的,而是需要表示“什么变化”和什么“保持不变”。据我所知,将来你可能会定义一个 MobileDevice,VirtualMobileDevice。

在您当前的课程中,您似乎拥有 Vendor、Serial 等属性。 MobileDevice 中可能也需要这些,对吗?所以你需要改变你的想法,真正考虑行为而不是具有层次意义的类。

再想一想,你正走在多重继承的轨道上,这是非常危险和复杂的设计。这里有问题的不是你思维过程的正确性。它的问题是你编码一些东西,而在不久的将来有人在前面使它复杂化,无法修复。

java 中没有多重继承是出于这个原因,以确保您不会想到分层方式。

想想“工厂”(用于创建)、策略(用于通用功能/处理)。

已编辑:

事实上,您还应该考虑以库的形式创建层,以便对处理的主要部分进行完全抽象和控制。无论您打算对 Asset/Device 类做什么,都应该抽象到一个库中,该库可以通过更改来保护。

【讨论】:

  • 很有趣,谢谢。是的,你的未来类型的例子是正确的。根据资产类型进行扩展的能力将非常有益于现在进行整理,而不是必须在很久以后才回来并向上推进根核心管道。 ...行为,我会考虑这个。
【解决方案4】:

使用混合。

您首先决定您希望您的对象成为的主要事物。在你的情况下,我认为它应该是服务器。

public class PhysicalServer : Server

然后为其他功能添加接口。

public class PhysicalServer : Server,IAsset,IVirtualDevice

然后向接口添加扩展方法。

public static int WordCount(this IAsset asset)
{
  //do something on the asset
}

如果我的回答太简单,这里有一篇关于 mixins 的文章:http://www.zorched.net/2008/01/03/implementing-mixins-with-c-extension-methods/

【讨论】:

    猜你喜欢
    • 2010-09-27
    • 2012-06-02
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多