【问题标题】:Methods which wrap a single method包装单个方法的方法
【发布时间】:2010-02-24 14:26:58
【问题描述】:

我觉得我快疯了,请有人安慰我。

public class MyFile
{   
    public static byte[] ReadBinaryFile(string fileName)
    {
        return File.ReadAllBytes(fileName);
    }

    public static void WriteBinaryFile(string fileName, byte[] fileContents)
    {
        File.WriteAllBytes(fileName, fileContents);
    }
}

人们不断将上述代码添加到我们的代码库中,这肯定是错误和可怕的,我通过删除它并替换所有(或在这种情况下同时替换......)对它的引用来帮助世界带有内部代码。

这种事情有什么真正的理由吗?我会错过更大的图景吗?在我们的团队中,我们以YAGNI 为中心,这似乎与这一点背道而驰。我可以理解这是否是更多事情的开始,但是这段代码已经休眠了好几个月,直到我今天绊倒它。我搜索的越多,我发现的越多。

【问题讨论】:

    标签: c# .net api coding-style


    【解决方案1】:

    正如所写,类/方法是垃圾。但是,我可以看到可能合法使用 similar 模式的情况:

    public interface IFileStorage
    {
        byte[] ReadBinaryFile(string fileName);
        void WriteBinaryFile(string fileName, byte[] fileContents);
    }
    
    public class LocalFileStorage : IFileStorage { ... }
    
    public class IsolatedFileStorage : IFileStorage { ... }
    
    public class DatabaseFileStorage : IFileStorage { ... }
    

    换句话说,如果您想支持不同类型的存储,那么您实际上可以包装非常简单的方法以实现通用抽象。

    尽管如此,该类并没有实现任何接口,而且方法是静态的,所以它几乎没有用处。如果您尝试支持上述模式,请重构;否则,摆脱它。

    【讨论】:

    • 这是一个更好的方法:D
    【解决方案2】:

    这很愚蠢,直到您考虑隐藏这些方法的实现细节。

    举个例子,如果你有这样的代码

    File.WriteAllBytes(fileName, fileContents);
    

    分散在您的代码中,如果有一天您想更改应用程序写入文件的方法怎么办?那么在这种情况下,您将不得不遍历您的代码并更新所有这些代码行以采用新方法,而与上述版本一样,您只需在一个地方进行更改。

    我不是说他们的方法是对的,你纠正它是错的,我只是补充一些观点

    【讨论】:

    • 担心不太可能发生的变化会污染代码库——这使它们更难理解和维护。
    • 好点。如果我们需要对代码库进行更改,拥有一个用于写入磁盘的集中点可能会获得回报。虽然我不认为这是这里的动机;)
    • 我理解并同意,只是添加了我认为的那些开发人员的想法
    • @Jeff:我同意担心不太可能发生的变化不应该是这种事情的唯一动机,但这并不是隐藏方法背后的实现细节的唯一原因. GetCustomerDataFileAsByteArray() 提供比 File.ReadAllBytes() 更多的上下文,恕我直言,更可取。
    • @Seth:肯定有一个面向上下文的、面向领域的抽象的地方,但我认为它处于更高的层次,比如GetCustomer(string sourceFilePath) 方法。然后 那个 方法将直接处理出色的、经过良好测试的 .NET API,而不是处理不添加任何行为并且可能成为未来错误位置的外观。
    【解决方案3】:

    那些方法的存在是令人作呕的偏差,应该立即纠正。

    它们可能是由不知道 File 类的人编写的,然后由知道但没有你那么大胆的人重写。

    【讨论】:

    • 如果我能得到两张票,一张是“令人作呕的失常”,另一张是“大胆”:)
    【解决方案4】:

    如果所有方法都采用相同的参数列表并传递它们,那么不,这是没有意义的,我认为实际上使代码less可以理解。但是,如果该方法除了作为参数传递的值之外,还传递了默认值,或者对参数进行了某种常见的验证,那么它的参数就更难了。

    这些方法是否占位符以供以后添加逻辑?如果是这样,那么应该添加 cmets 甚至可怕的 TODO 语句,以便稍后有人回绕并完成这个想法。

    【讨论】:

      【解决方案5】:

      我认为这些方法作为辅助类的静态方法没有多大意义,但这种模式在某些情况下具有优点。例如:

      1. 将代码与静态类解耦。如果MyFile 不是静态的,那么它可以作为静态IO.File 对象的抽象。直接访问文件系统的代码可能很难测试,因此像这样的抽象可能很有用。 (例如,我有一个IFileSystem 接口,我的所有I/O 代码都依赖它,而我的FileSystem 类实现了这个接口并包装了File 的基本方法。)

      2. 在方法中保持一致的抽象级别。我不喜欢将 问题域 中的代码(例如“客户”和“订单”)与 _solution 域中的代码(文件和字节和位)混合。我经常会编写这样的包装器,以使代码更易于阅读并为我提供可扩展性点。我宁愿阅读GetDataFileContents() 而不是File.ReadAllBytes("foo.dat")

      3. 提供上下文。如果因为它的副作用而执行一段代码,例如删除一个文本文件来影响客户订单的删除,那么我更喜欢阅读DeleteCustomerOrderFile("foo.txt")而不是File.Delete("foo.txt")。前者为代码提供上下文信息,后者不提供。

      【讨论】:

      • 第 1 点是我真正想要长期对这门课做的事情,以帮助测试/模拟等,但今天的优先级不是。
      【解决方案6】:

      我想这个问题的答案确实取决于您的团队、实践以及代码的最终目的是什么(例如。您发现的代码段当前写入文件但将写入 Web 服务/数据库/morse-code machine 一旦完成 - 虽然那个“借口”有点被类/方法名打败了)。我想你已经用“我们的团队非常以 YAGNI 为中心,而这似乎与这一点相悖”回答了这个问题。

      不过,最终的答案是问写它的人为什么要这样写。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-24
        • 2015-04-08
        • 2011-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-08
        相关资源
        最近更新 更多