C# - 在子 classes 中调用个别行为后,在抽象 class 中添加公共行为

C# - Add common behaviour in abstract class after calling individual behaviours in subclasses

我对抽象 classes 很陌生。通常你可以在 base-class 中创建一个成员,然后通过使用 base.Member 在 subclass 中调用它来扩展它的逻辑。但是我可以反过来做吗?

我有一个 abstract class A 和 属性 类型 IEnumerable<T>:

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

我希望 A 的派生 classes 到 return 一个单独的 IEnumerable,并希望在相同条件下使用 .Where "filter" 它们。我做了以下操作:

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; }
    }
}

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

这个方法就好了。

您有一个符合 DRY 原则的基础 class 中所有派生的 classes (.Where()) 共有的行为。

那么在那些 classes 中,每个派生的 class 都有特定的行为。

It feels especially clunky if I have some classes between which also have to filter it because I'd just have to add more and more members based on the amount of layers I have.

好吧,如果你需要对不同的情况有不同的逻辑,那就太好了。

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

这样考虑:在定义抽象 Bar 时,您说的是 "all implementations can 'Bar'",然后当您从 Foo 调用它时,这是完美的,因为所有实现都可以 'Bar'.

It feels especially clunky if I have some classes between which also have to filter it because I'd just have to add more and more members based on the amount of layers I have.

您的意思是其他 类 也在对同一个可枚举对象执行 Where() 吗?别介意; A 做的是 Foo 的意思,子类做的是 Bar 的意思,不管是不是另一个 Where()A。 (有时我们确实必须打破这个规则,如果它被证明是一个性能热点,但首先初始设计不是考虑这一点的地方,其次 Enumerable.Where() 实际上已经针对 [的顺序调用进行了优化=12=] 关于 Where() 的结果)。

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

对于你正在努力做的事情,很好,你想留着就留着。但是,这不是唯一的解决方案。

The Strategy Pattern

当您只有 1 种方法时,有时建议注入一个对象来做这 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 都实现的实际接口。当您谈论添加其他 class 过滤器时,这确实可以很好地扩展。然后可以实例化您的 classes 以执行您想要的过滤。