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

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

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

资产开始...

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

每个 PhysicalServer 都需要同时是 PhysicalDeviceServer
每个 VirtualServer 都需要是 VirtualDeviceServer
每一个NetDevice都是一个PhysicalDevice
每个 StorageArray 都是一个 PhysicalDevice

我想一个解决方案是为 PhysicalServersVirtualServers 复制 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# 不支持类的多重继承(但支持接口的多重实现)。

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

但是,您最终会得到一个可能很复杂的类层次结构,并且许多人会主张 组合 而不是 继承。在这里,您将拥有定义行为的接口,并且类实现该接口以表示它们执行某些操作,但是每个类可以以不同的方式实现接口方法。因此,您的 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
    相关资源
    最近更新 更多