我对抽象类很新。通常,您可以在基类中创建成员,然后通过使用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; }
}
}
它有效,但这是正确的方法吗?或者我可以只使用一个属性做同样的事情?如果我有一些类也必须过滤它,因为我只需要根据我拥有的层数添加越来越多的成员,这种感觉特别笨重。
答案 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;
}
}
这有点简化,您可能需要A
和B
实现的实际接口。当你谈到添加其他过滤类时,这确实很好。然后可以实例化您的类以进行所需的过滤。