【问题标题】:c# OOD problem with generic collections and interfacesc# 泛型集合和接口的 OOD 问题
【发布时间】:2021-07-09 10:50:53
【问题描述】:

我正在尝试以以下方式对问题进行建模:

  1. Schedule.Products 集合可以同时包含:IProducts 和 IProductsWithConfig
  2. ProductWithConfig.Config 集合只能包含 IProducts 而不是 IProductsWithConfig

我有点卡住了——就像现在一样(如下),我无法阻止将 IProductsWithConfig 添加/包含在 ProductWithConfig.Config 中。任何想法如何以优雅的方式对其进行编码?

    interface ISchedule
    {
        IEnumerable<IProduct> Products { get; set; }
    }

    interface IProductWithConfig : IProduct
    {
        IEnumerable<IProduct> Config { get; set; }
    }

    interface IProduct
    {
        int Id { get; set; }
    }

【问题讨论】:

  • 我不知道它如何适合您的设计,但如果您有另一个继承 IProduct 的接口 - 比如说 IPlainProduct - 那么这将是 is-a IProduct 而不是 is-a IProductWithConfig。 ..你可以有IEnumerable&lt;IPlainProduct&gt; Config { get; set; }
  • @Fildor 但 IPlainProduct 将是一个从 IProduct 继承的空接口?
  • 可能是。但这并没有什么坏处。
  • 其实,如果我没记错的话,我认为第 2 点违反了里氏替换原则。
  • 基本上这里的问题是:你设计的“有一个配置”意味着“成为一个潜在的配置元素”。但是在您的第二个要求中,您将“拥有配置”和“成为配置”单向独占。想想这个和我上面的解决方案:它甚至可能还不够。如果你有一个实现两个接口的类(这是完全合法的)怎么办? ...

标签: c# oop generics collections interface


【解决方案1】:

继承的想法是,您可以在需要 IProduct 的任何情况下使用 IProduct 的任何派生版本。根据定义,实现 IProductWithConfig 的类的每个实例都是实现 IProduct 的实例。 Fildor 的评论很有道理:将 IProduct 抽象化并从中创建一个新的后代。

或者您可以隐藏公共属性 Config 并通过 Add(Product) 和只读 IEnumerable 等一些方法公开这些属性。然后您可以控制将哪些类型的对象添加到集合中。

【讨论】:

  • 我希望我可以使用一些我还不太熟悉的 co/contra-variance 技巧。
  • @adam.k 反或协方差只会阻止您将List&lt;IDerivedFromIProduct&gt; 分配给您的IEnumerable&lt;IProduct&gt;,但我可以很高兴地将一个对象添加到该可枚举对象,只要它is-a IProduct .这意味着它在树上的某个地方实现了该接口。
猜你喜欢
  • 1970-01-01
  • 2011-03-21
  • 2012-09-02
  • 1970-01-01
  • 2011-04-28
  • 2020-06-14
  • 2011-04-01
  • 2011-06-14
  • 1970-01-01
相关资源
最近更新 更多