关于C:用单一方法的类-最佳方法?

Class with single method — best approach?

假设我有一个要执行单个函数的类。执行该功能后,可以将其销毁。有没有理由选择这些方法中的一种?

1
2
3
4
5
6
7
8
9
10
// 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()。我在考虑更多的类,它们执行一些特定的、复杂的任务,但只需要一个(公共)方法来完成。


我以前喜欢用静态方法填充的实用程序类。他们对helper方法进行了大量的整合,否则这些方法会导致冗余和维护问题。它们很容易使用,没有实例化,没有处置,只是火不忘。我想这是我第一次无意中尝试创建面向服务的体系结构——许多无状态的服务只做了他们的工作,其他什么都没有。然而,随着一个系统的发展,龙就要来了。好的。

多态性
假设我们有一个方法utilityClass.somemethod,它会很高兴地蜂拥而至。突然我们需要稍微改变一下功能。大多数功能都是相同的,但是我们仍然需要更改几个部分。如果不是静态方法,我们可以创建一个派生类,并根据需要更改方法内容。因为它是一个静态方法,所以我们不能。当然,如果我们只需要在旧方法之前或之后添加功能,我们可以创建一个新的类,并在其中调用旧的类——但这很恶心。好的。

接口问题
由于逻辑原因,无法通过接口定义静态方法。由于我们不能重写静态方法,当我们需要通过接口传递静态类时,静态类是无用的。这使得我们无法将静态类用作策略模式的一部分。我们可以通过传递委托而不是接口来修补一些问题。好的。

测试
这与上面提到的接口问题基本上是一致的。由于我们交换实现的能力非常有限,因此我们也很难用测试代码替换生产代码。同样,我们可以将它们包装起来,但这将要求我们更改代码的大部分,以便能够接受包装器而不是实际对象。好的。

促进斑点
由于静态方法通常用作实用方法,而实用方法通常具有不同的用途,因此我们很快就会得到一个大类,其中充满了不一致的功能——理想情况下,每个类在系统中都应该有一个单独的用途。我更愿意有一个五倍的类,只要它们的目的是明确的。好的。

参数蠕变
首先,这个可爱而天真的静态方法可能只需要一个参数。随着功能的增长,会添加一些新参数。很快会添加更多可选的参数,因此我们创建方法的重载(或者只添加支持它们的语言中的默认值)。不久,我们就有了一个方法,它需要10个参数。只需要前三个参数,参数4-7是可选的。但如果指定参数6,则也需要填写7-9…如果我们创建一个类的唯一目的是做这个静态方法所做的,我们可以通过在构造函数中输入所需的参数来解决这个问题,并允许用户通过属性设置可选值,或者方法同时设置多个相互依赖的值。另外,如果一个方法已经变得如此复杂,那么它很可能无论如何都需要在自己的类中。好的。

无理由要求消费者创建类的实例
最常见的一个参数是,为什么要求类的使用者创建一个用于调用这个方法的实例,而随后对该实例没有任何用处?在大多数语言中,创建类的实例是非常便宜的操作,因此速度不是问题。向消费者添加一个额外的代码行是一个低成本,为将来提供一个更可维护的解决方案奠定了基础。最后,如果您想避免创建实例,只需创建类的单例包装器,以便于重用——尽管这确实要求您的类是无状态的。如果它不是无状态的,那么您仍然可以创建处理所有事情的静态包装方法,同时从长远来看仍然可以给您带来所有好处。最后,您还可以创建一个隐藏实例化的类,就像它是一个单例:mywrapper.instance是一个只返回new myclass()的属性;好的。

只有西斯才是绝对的。当然,我不喜欢静态方法也有例外。对于静态方法(system.convert)来说,真正的实用程序类不会对膨胀造成任何风险,这是很好的例子。如果您的项目是一次性的,没有未来维护的需求,那么整个体系结构实际上并不重要——静态的或非静态的,并不重要——但是开发速度确实如此。好的。

标准,标准,标准!< BR>使用实例方法不会禁止您也使用静态方法,反之亦然。只要差异背后有推理,而且是标准化的。没有什么比用不同的实现方法查看业务层更糟糕的了。好的。好啊。


我更喜欢静态的方式。由于类不表示对象,因此创建它的实例是没有意义的。

只为其方法存在的类应保持静态。


如果没有理由创建类的实例来执行函数,那么使用静态实现。为什么让这个类的使用者在不需要实例的时候创建一个实例。


如果不需要保存对象的状态,那么首先就不需要实例化它。我将使用您传递参数的单个静态方法。

我还警告过一个巨大的utils类,它有几十个不相关的静态方法。这会很快变得混乱和笨拙。最好有许多类,每个类都有一些相关的方法。


我认为静态方法格式是更好的选择。我也会使类成为静态的,这样就不必担心意外地创建类的实例。


我真的不知道这里的情况是什么,但是我会把它作为一个方法放在arg1、arg2或arg3所属的类中——如果你能语义上说其中一个类拥有这个方法的话。


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

我的直觉是,如果你只需要一个方法,并且你要立即丢弃这个类,然后把它变成一个静态类,它接受所有参数。

当然,很难说清楚为什么只需要为这个方法创建一个类。这是大多数人假设的典型的"公用事业类"情况吗?或者您正在实现某种类型的规则类,将来可能会有更多的规则类。

例如,让这个类是可插入的。然后您需要为您的一个方法创建一个接口,然后您需要将所有参数传递到接口,而不是传递到构造函数,但是您不希望它是静态的。


对于简单的应用程序和internal助手,我将使用静态方法。对于带有组件的应用程序,我喜欢托管扩展性框架。下面是我正在编写的一个文档的摘录,它描述了您将在我的API中找到的模式。

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

作为一个人为的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
        }
    }
}

如果此方法是无状态的,并且不需要传递它,那么将其定义为静态的方法是最有意义的。如果您确实需要传递方法,您可以考虑使用委托,而不是其他建议的方法之一。


你的课能静下来吗?

如果是这样,那么我会把它变成一个"实用程序"类,我会把我所有的一个函数类都放进去。


我会在构造器中做所有的事情。像这样:

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

1
MyClass my_object(arg1, arg2, arg3);


我认为,如果类的属性或类的实例不会在构造函数或方法中使用,则不建议将方法设计为"静态"模式。静态方法应该总是以"帮助"的方式考虑。


你也许可以一起避免这种情况。尝试重构以便获得arg1.myMethod1(arg2, arg3)。如果更合理,请将arg1与arg2或arg3交换。

如果您没有对arg1类的控制权,请装饰它:

1
2
3
4
5
6
7
8
9
10
11
12
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中,数据和方法处理数据属于一起。此外,你还可以获得马克提到的所有优势。


需要考虑的一个更重要的问题是系统是否在多线程环境下运行,以及拥有静态方法或变量是否是线程安全的…

您应该注意系统状态。