C# - 在子类中调用各个行为后,在抽象类中添加常见行为

时间:2017-11-14 09:21:05

标签: c# inheritance polymorphism abstract

我对抽象类很新。通常,您可以在基类中创建成员,然后通过使用base.Member在子类中调用它来扩展其逻辑。但我可以反过来这样做吗?

我有一个abstract class A,其属性类型为IEnumerable<T>

abstract class A
{
    IEnumerable<int> Foo { get; }
}

我希望A的派生类返回单个IEnumerable,并希望使用.Where以相同的条件“过滤”它们。我做了以下事情:

abstract class A
{
    public IEnumerable<int> Foo => Bar.Where(x => true);
    protected abstract IEnumerable<int> Bar { get; }
}
abstract class B : A
{
    protected override IEnumerable<int> Bar {
        get { yield return 1; }
    }
}

它有效,但这是正确的方法吗?或者我可以只使用一个属性做同样的事情?如果我有一些类也必须过滤它,因为我只需要根据我拥有的层数添加越来越多的成员,这种感觉特别笨重。

3 个答案:

答案 0 :(得分:2)

这种方法很好。

基类中的所有派生类(.Where())都有一个符合DRY原则的行为。

然后,您将拥有特定于这些类中每个派生类的行为。

  

如果我还有一些课程,那感觉特别笨重   必须过滤它,因为我只需要添加越来越多的成员   根据我拥有的图层数量。

嗯,如果您需要针对不同情况使用不同的逻辑,那就完全没问题了。

答案 1 :(得分:1)

这是一个非常标准的习语。

因此考虑一下:在定义摘要Bar时,您要说&#34;所有实现都可以&#39; Bar&#39;&#34;,然后当您从{ {1}}因为所有的实施都可以&#39; Bar&#39;。

  

如果我有一些课程也必须过滤它,这感觉特别笨重,因为我只需要根据我的图层数量添加越来越多的成员。

你的意思是其他类也对同一个可枚举的Foo做了什么?不要小心; Where()正在执行A的含义,而子类正在执行Foo对它的意义,以及是否还有其他Bar不值得担心约在Where()。 (有时我们必须违反该规则,如果它被证明是一个性能热点,但首先,初始设计不是一个考虑它的地方,其次A实际上已经针对{的顺序调用进行了优化无论如何Enumerable.Where()的结果{1}}。

答案 2 :(得分:0)

这里有你的 Template Method Pattern 。当您有多个受保护的抽象方法时,这尤其适用,其中抽象类控制这些方法的流程。

对于你想要做的事情,它很好,如果你愿意,你可以保留它。但是,它不是唯一的解决方案。

<强> The Strategy Pattern

当你只有1个方法时,有时会建议注入一个执行该操作的对象。这更容易扩展,因为对于每个新的B,您只需要测试它的细节,而不是抽象所做的部分。

最后,我认为您的情况最适合 The Decorator Pattern

class B
{
    public IEnumerable<int> Foo => yield return 1;
}
class A : B
{
    private B b;
    public IEnumerable<int> Foo => b.Foo.Where(x => true);

    public A(B b)
    {
        this.b = b;
    }
}

这有点简化,您可能需要AB实现的实际接口。当你谈到添加其他过滤类时,这确实很好。然后可以实例化您的类以进行所需的过滤。