题
说我有一个类意味着要执行一个单一的功能。在进行功能,它可以摧毁。是否有任何理由喜欢这个方法?
// 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);
我是故意模糊的有关详情,以试图让指导方针对于不同的情况。但是我没有真的有头脑简单的图书馆功能,如数学。随机().我在想更多的课程,执行一些具体的、复杂的任务,但仅仅需要一种(公共)方法做到这一点。
解决方案
我曾经喜欢充满静态方法的实用工具类。他们对辅助方法进行了很好的整合,否则会导致冗余和维护。它们非常容易使用,没有实例化,没有处置,只是火不会忘记。我想这是我第一次不知不觉地尝试创建面向服务的体系结构 - 许多无状态服务只是完成了自己的工作而没有其他工作。然而,随着系统的发展,龙将会到来。
<强>多态性强>结果 假设我们有方法UtilityClass.SomeMethod愉快地嗡嗡作响。突然间我们需要稍微改变功能。大多数功能都是相同的,但我们必须改变几个部分。如果它不是静态方法,我们可以创建一个派生类并根据需要更改方法内容。因为它是一种静态方法,我们不能。当然,如果我们只需要在旧方法之前或之后添加功能,我们可以创建一个新类并在其中调用旧类 - 但这只是粗略的。
界面困境
由于逻辑原因,无法通过接口定义静态方法。由于我们无法覆盖静态方法,因此当我们需要通过接口传递静态类时,静态类是无用的。这使我们无法使用静态类作为策略模式的一部分。我们可以通过修补一些问题。传递代理而不是接口。
<强>测试强>结果 这基本上与上面提到的界面问题密切相关。由于我们交换实现的能力非常有限,我们也很难用测试代码替换生产代码。同样,我们可以将它们包装起来,但它需要我们更改代码的大部分内容,以便能够接受包装而不是实际的对象。
促进blob
由于静态方法通常用作实用方法,而实用方法通常会有不同的用途,我们很快就会得到一个充满非连贯功能的大类 - 理想情况下,每个类在系统中应该有一个目的。只要他们的目的明确定义,我宁愿拥有五次课程。
参数creep
首先,这个小巧可爱且无辜的静态方法可能需要一个参数。随着功能的增长,添加了几个新参数。很快又添加了可选的参数,因此我们创建了方法的重载(或者只是在支持它们的语言中添加默认值)。不久,我们有一个方法,需要10个参数。实际上只需要前三个,参数4-7是可选的。但是如果指定了参数6,则需要填写7-9 ...如果我们创建了一个具有执行此静态方法的单一目的的类,我们可以通过获取所需的参数来解决这个问题。构造函数,并允许用户通过属性或方法设置可选值,以同时设置多个相互依赖的值。此外,如果一种方法已经发展到这种复杂程度,那么无论如何它很可能都需要在自己的类中。
要求消费者无缘无故地创建课程实例
最常见的一个论点是,为什么要求我们类的使用者创建一个用于调用这个方法的实例,而之后却没有使用该实例?在大多数语言中创建类的实例是非常便宜的操作,因此速度不是问题。向消费者添加额外的代码行是为将来构建更易维护的解决方案奠定基础的低成本。最后,如果您想避免创建实例,只需创建一个singleton wra
其他提示
我更喜欢静态方式。由于Class不表示对象,因此创建它的实例是没有意义的。
只应为其方法存在的类应保持静态。
如果没有理由为了执行该函数而创建类的实例,那么使用静态实现。为什么让这个类的使用者在不需要时创建一个实例。
如果您不需要保存对象的状态,则无需首先实例化它。我将使用您将参数传递给的单一静态方法。
我还要警告一个巨大的Utils类,它有许多不相关的静态方法。这可能会匆忙地变得杂乱无章。最好有很多类,每个类都有很少的相关方法。
我会说静态方法格式是更好的选择。而且我也会让类静态化,这样你就不必担心意外地创建类的实例。
我真的不知道这里的情况是什么,但我会把它作为一个方法放在arg1,arg2或arg3所属的类中 - 如果你可以在语义上说那些类中的一个将拥有该方法。
我建议根据提供的信息很难回答。
我的直觉是,如果你只是想要一个方法,并且你要立即抛弃类,那么将它作为一个带有所有参数的静态类。
当然,很难确切地说明为什么需要为这一个方法创建单个类。它是典型的“公用事业类”吗?大多数人都假设的情况?或者您正在实施某种规则类,未来可能会有更多规则类。
例如,让该类可插入。然后你想为你的一个方法创建一个接口,然后你想要将所有参数传递到接口,而不是传递给构造函数,但你不希望它是静态的。
你的班级可以变得静止吗?
如果是这样,那么我会把它变成一个'Utilities'类,我会将所有的单函数类放入其中。
如果此方法是无状态的并且您不需要传递它,那么将它定义为静态是最有意义的。如果您需要传递方法,可以考虑使用委托,而不是您提出的其他方法之一。
对简单的应用程序和 internal
助手,我想用一个静态的方法。为应用成分,我爱的 管理扩展框架.这里有一个摘自一份文件,我写描述的模式,你会发现在我的Api。
- 服务
- 定义
I[ServiceName]Service
接口。 - 出口和进口通过该接口的类型。
- 单的实施是提供主机应用程序和国内消费和/或通过扩展。
- 方法上的服务界线的安全。
- 定义
作为一个人为的例子:
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);
需要考虑的另一个重要问题是系统是否将在多线程环境中运行,以及是否具有静态方法或变量的线程安全......
你应该注意系统状态。
你或许可以一起避免这种情况。尝试重构,以便获得 arg1.myMethod1(arg2,arg3)
。
如果更有意义的话,用arg2或arg3交换arg1。
如果你无法控制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中,处理数据的数据和方法属于一起。此外,您还可以获得Mark所提到的所有优势。
我认为,如果您的类的属性或类的实例不会在构造函数或方法中使用,则不建议将方法设计为“静态”模式。应始终以“帮助”的方式思考静态方法。