gpt4 book ai didi

c# - "Program to an interface"使用扩展方法 : When does it go too far?

转载 作者:太空狗 更新时间:2023-10-29 20:21:16 25 4
gpt4 key购买 nike

背景本着"program to an interface, not an implementation"的精神和 Haskell type classes ,并且作为一个编码实验,我正在考虑创建一个主要基于接口(interface)和扩展方法组合的 API 意味着什么。我有两条准则:

  1. 尽可能避免类继承。接口(interface)应实现为 sealed class es.
    (这有两个原因:首先,因为子类化引发了一些关于如何在其派生类中指定和执行基类契约的令人讨厌的问题。其次,这是 Haskell 类型类的影响,多态性不需要子类化.)

  2. 尽可能避免使用实例方法。如果可以用扩展方法来完成,这些是首选。
    (这旨在帮助保持接口(interface)紧凑:可以通过组合其他实例方法完成的所有操作都成为扩展方法。接口(interface)中保留的是核心功能,尤其是状态更改方法。)

问题:我在使用第二条指南时遇到了问题。考虑一下:

interface IApple { }
static void Eat(this IApple apple)
{
Console.WriteLine("Yummy, that was good!");
}

interface IRottenApple : IApple { }
static void Eat(this IRottenApple apple)
{
Console.WriteLine("Eat it yourself, you disgusting human, you!");
}

sealed class RottenApple : IRottenApple { }
IApple apple = new RottenApple();
// API user might expect virtual dispatch to happen (as usual) when 'Eat' is called:
apple.Eat(); // ==> "Yummy, that was good!"

显然,对于预期结果 ( "Eat it yourself…" ),Eat应该是一个常规的实例方法。

问题:关于使用扩展方法与(虚拟)实例方法的改进/更准确的指南是什么?什么时候使用扩展方法来“编程到接口(interface)”太过分了?在什么情况下实际需要实例方法?

我不知道是否有明确的通用规则,所以我不期待一个完美的通用答案。对上述准则 (2) 的任何有争议的改进表示赞赏。

最佳答案

您的指导方针已经足够好了:它已经说“只要有可能”。因此,真正的任务是在更多细节中阐明“尽可能”这一点。

我使用这个简单的二分法:如果添加方法的目的是隐藏子类之间的差异,则使用扩展方法;如果目的是突出差异,请使用虚拟方法。

您的 Eat 方法是在子类之间引入差异的方法示例:吃(或不吃)苹果的过程取决于苹果的种类。因此,您应该将其实现为实例方法。

ThrowAway 是一个试图隐藏差异的方法示例:

public static void ThrowAway(this IApple apple) {
var theBin = RecycleBins.FindCompostBin();
if (theBin != null) {
theBin.Accept(apple);
return;
}
apple.CutUp();
RecycleBins.FindGarbage().Accept(apple);
}

如果不管苹果的种类如何,扔掉苹果的过程都是相同的,那么该操作很适合在扩展方法中实现。

关于c# - "Program to an interface"使用扩展方法 : When does it go too far?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11441905/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com