单一方法的类 – 最好的方法?

假设我有一个课程是为了完成一个单一的function。 执行该function后,可以销毁。 有没有任何理由更喜欢这些方法之一?

// Initialize arguments in constructor MyClass myObject = new MyClass(arg1, arg2, arg3); myObject.myMethod(); // Pass arguments to method MyClass myObject = new MyClass(); myObject.myMethod(arg1, arg2, arg3); // Pass arguments to static method MyClass.myMethod(arg1, arg2, arg3); 

我故意模糊的细节,试图得到不同情况的指导方针。 但是我并没有真正想到像Math.random()这样简单的库函数。 我正在考虑更多的类执行一些特定的,复杂的任务,但只需要一个(公共)的方法来做到这一点。

我曾经喜欢充满静态方法的工具类。 他们对辅助方法进行了大量整合,否则这些方法会导致冗余和维护地狱。 他们很容易使用,没有实例化,没有处理,只是fire'n'forget。 我想这是我第一次不知情的创build一个面向服务的架构的尝试 – 大量的无状态的服务,只是他们的工作,没有别的。 随着系统的发展,龙即将到来。

多态性
假设我们有方法UtilityClass.SomeMethod愉快地嗡嗡声。 突然,我们需要稍微改变function。 大部分的function是一样的,但是我们必须改变几个部分。 如果不是一个静态方法,我们可以根据需要制作派生类并更改方法内容。 由于这是一个静态的方法,我们不能。 当然,如果我们只需要在旧方法之前或之后添加function,我们就可以创build一个新类并在其中调用旧类,但这只是粗略的。

界面的困扰
出于逻辑原因,静态方法不能通过接口定义。 而且由于我们不能重载静态方法,所以当我们需要通过接口传递它们时,静态类就没有用处了。 这使我们无法使用静态类作为策略模式的一部分。 我们可以通过传递委托代替接口来修补一些问题。

testing
这基本上与上面提到的接口问题一起。 由于我们交换实现的能力非常有限,所以在使用testing代码replace生产代码时也会遇到困难。 再次,我们可以把它们包装起来,但是它需要我们改变大部分的代码,只是为了能够接受包装器而不是实际的对象。

促进斑点
由于静态方法通常被用作效用方法,效用方法通常会有不同的用途,所以我们很快就会得到一个充满非一致性function的大类 – 理想情况下,每个类在系统中应该有一个单一的目的。 只要他们的目标明确,我宁愿有五次class。

参数蠕变
首先,那个可爱又天真的静态方法可能只有一个参数。 随着function的增长,添加了一些新的参数。 不久,进一步添加的参数是可选的,所以我们创build方法的重载(或只是添加默认值,支持它们的语言)。 不久,我们有一个方法需要10个参数。 只有前三个是必需的,参数4-7是可选的。 但是,如果指定了参数6,那么也需要填充7-9 …如果我们创build了一个具有这个静态方法所做的单一目的的类,我们可以通过在构造函数,并允许用户通过属性设置可选值,或者同时设置多个相互依赖的值的方法。 而且,如果一个方法已经发展到这个复杂的程度,反正它最有可能需要在自己的类中。

要求消费者没有理由地创build一个类的实例
最常见的争论之一是,为什么要求我们的类的消费者创build一个调用这个单一方法的实例,而之后又没有使用这个实例呢? 在大多数语言中创build一个类的实例是非常非常便宜的操作,所以速度不是问题。 向消费者添加额外的代码行是为将来更可维护的解决scheme打下基础的低成本。 最后,如果你想避免创build实例,只需创build一个允许轻松重用的类的单例包装器(singleton wrapper),尽pipe这确实要求你的类是无状态的。 如果它不是无状态的,那么仍然可以创build静态包装方法来处理所有事情,同时仍然可以长期为您提供所有的好处。 最后,你也可以创build一个隐藏实例的类,就好像它是一个单例:MyWrapper.Instance是一个只返回新MyClass()的属性。

只有一个西斯交易绝对
当然,我也不喜欢静态方法。 真正的实用程序类别不会造成任何膨胀风险,这是静态方法的绝佳例子 – 以System.Convert为例。 如果你的项目是一次性的,对未来的维护没有任何要求,那么整体架构确实不是非常重要的 – 静态或者非静态,并不重要,但是开发速度确实是这样。

标准,标准,标准!
使用实例方法不会阻止您使用静态方法,反之亦然。 只要分化背后有推理,标准化。 没有什么比通过不同的实现方法来查看业务层更糟了。

我更喜欢静态的方式。 由于该类不代表一个对象,因此build立它的一个实例是没有意义的。

仅存在于其方法中的类应保持静态。

如果没有理由为了执行该函数而创build类的实例,则使用静态实现。 为什么这个类的消费者在不需要的时候创build一个实例。

如果你不需要保存对象的状态 ,那么不需要首先实例化它。 我会去与你传递参数的单个静态方法。

我也会警告一个巨大的Utils类,它有很多不相关的静态方法。 这可能会很混乱,笨拙。 有很多类,每个都有很less的相关方法。

我真的不知道这里的情况是什么,但是我会考虑把它作为arg1,arg2或arg3所属的一个类中的一个方法 – 如果你可以在语义上说这些类中的一个拥有方法。

我会说静态方法格式将是更好的select。 而且我也会让这个类变成静态的,这样你就不必担心无意中创build了一个类的实例。

我build议根据所提供的信息很难回答。

我的直觉是,如果你只是要有一个方法,而且要立即抛出这个类,那么就把它变成一个静态类,它接受所有的参数。

当然,很难说出为什么你需要为这一个方法创build一个类。 大多数人认为这是典型的“公用事业class”吗? 或者你正在执行某种规则类别,将来可能会有更多规则类别。

例如,那个类是可以插入的。 然后你想为你的一个方法创build一个接口,然后你想把所有的parameter passing给接口,而不是构造函数,但是你不希望它是静态的。

你的课堂可以静止吗?

如果是这样的话,那么我会把它变成一个“实用工具”类,我将把所有的单一function类放入其中。

如果这个方法是无状态的,你不需要传递它,那么把它定义为静态是最有意义的。 如果你需要传递方法,你可以考虑使用一个委托,而不是你提出的其他方法之一。

对于简单的应用程序和internal帮助器,我将使用静态方法。 对于具有组件的应用程序,我喜欢托pipe扩展性框架 。 以下是我正在撰写的文档摘录,描述您可以在我的API中find的模式。

  • 服务
    • 由一个I[ServiceName]Service接口定义。
    • 通过接口types导出和导入。
    • 单个实现由主机应用程序提供,并在内部和/或扩展中使用。
    • 服务接口上的方法是线程安全的。

作为一个人为的例子:

 public interface ISettingsService { string ReadSetting(string name); void WriteSetting(string name, string value); } [Export] public class ObjectRequiringSettings { [Import] private ISettingsService SettingsService { get; set; } private void Foo() { if (SettingsService.ReadSetting("PerformFooAction") == bool.TrueString) { // whatever } } } 

我只是在构造函数中做所有事情。 像这样:

 new MyClass(arg1, arg2, arg3);// the constructor does everything. 

要么

 MyClass my_object(arg1, arg2, arg3); 

还有一个要考虑的重要问题是系统是否在multithreading环境下运行,以及是否有线程安全的静态方法或variables。

你应该注意系统状态。

你可能能够一起避免这种情况。 尝试重构,以便获得arg1.myMethod1(arg2, arg3) 。 如果arg2或arg3更有意义,则将arg1与arg2或arg3交换。

如果你不能控制arg1的类,那就修饰它:

 class Arg1Decorator private final T1 arg1; public Arg1Decorator(T1 arg1) { this.arg1 = arg1; } public T myMethod(T2 arg2, T3 arg3) { ... } } arg1d = new Arg1Decorator(arg1) arg1d.myMethod(arg2, arg3) 

原因在于,在OOP中,处理这些数据的数据和方法属于一个整体。 另外你得到了马克提到的所有优点。

我认为,如果你的类的属性或类的实例不会在构造函数或方法中使用,方法不build议像“静态”模式devise。 应始终以“帮助”的方式思考静态方法。