Helper / Utility Classes应该是抽象的吗?

时间:2008-11-21 17:27:11

标签: java abstract-class

我经常发现自己将类中的常见行为提取到helper / utility类中,这些类只包含一组静态方法。我经常想知道我是否应该将这些类声明为抽象类,因为我无法真正想到实例化这些类的正当理由?

优点和缺点是宣布这样一个类是抽象的。

public [abstract] class Utilities{

   public static String getSomeData(){
       return "someData";
   }

   public static void doSomethingToObject(Object arg0){
   }
}

11 个答案:

答案 0 :(得分:71)

你可以声明一个什么都不做的私有构造函数。

声明类“abstract”的问题在于abstract关键字通常意味着该类旨在进行子类化和扩展。这绝对不是你想要的。

答案 1 :(得分:18)

不要打扰它们是抽象的,而是包含一个私有的无参数构造函数来防止它们被实例化。

对于那些感兴趣的人来说比较点:在C#中你会声明这个类是静态的,在编译的表单中使它成为抽象的密封(Java的最终版),而根本没有任何实例构造函数。这也使得声明该类型的参数,变量,数组等成为编译时错误。方便。

答案 2 :(得分:9)

我没有声明实用程序类abstract,我将它们声明为final并使构造函数为private。这样它们就不能被子类化,也无法实例化。



public final class Utility
{
    private Utility(){}

    public static void doSomethingUseful()
    {
        ...
    }
}

答案 3 :(得分:3)

通过将它们声明为抽象,您实际上向其他编码器指示您打算从这些类派生。真的,你是对的,没有太大的区别,但这里的语义更多的是关于其他看你代码的人的解释。

答案 4 :(得分:3)

我会在私有构造函数之外添加更多步骤:

public class Foo {
   // non-instantiable class
   private Foo() { throw new AssertionError(); }
}

抛出AssertionError会阻止同一个类中的方法实例化类(好吧,他们可以尝试)。这通常不是问题,但在团队环境中,你永远不会知道某人会做什么。

关于“abstract”关键字,我注意到在很多实例中子类化的实用程序类:

public class CoreUtils { ... }
public class WebUtils extends CoreUtils { ... }

public class Foo { ... WebUtils.someMethodInCoreUtils() ... }

我相信这样做是为了让人们不必记住要包含哪个实用程序类。这有什么缺点吗?这是一种反模式吗?

此致 LES

答案 5 :(得分:2)

正如其他人所说,建立一个私有的无参数构造函数。除了类本身之外,没有人可以创建它的实例。

正如其他人已经展示了如何使用其他语言,以下是如何在下一个C ++版本中执行此操作,如何使类不可实例化:

struct Utility { 
    static void doSomething() { /* ... */ } 
    Utility() = delete; 
};

答案 6 :(得分:1)

我认为最好使用私有的无参数构造函数将实用程序类声明为final。此外,此类的所有成员都应该是静态的。

在一个语句中完成所有这些操作的一种简单方法是使用@UtilityClass annotation of Lombok

@UtilityClass
public class Utilities{

   public String getSomeData() {
       return "someData";
   }

   public void doSomethingToObject(Object arg0) {
   }
}

如果您使用@UtilityClass注释,则可以跳过上面的示例中的静态关键字,因为Lombok在编译过程中会自动添加它们。

答案 7 :(得分:0)

不,但是如果你的语言支持它,那就有一个强有力的论据,即在大多数情况下它们应该(可以)被声明为'静态'...静态告诉编译器它们不能被实例化,并且所有它们中的方法必须是静态的。

Abstract是针对具有基于实例的实现细节的类,将由派生类的实例使用...

答案 8 :(得分:0)

Helper / Utility方法很好。不要担心将它们添加到应用程序或框架内的库中。我见过的大多数框架都使用它们。

话虽如此,如果你想对它们变得非常狡猾,你应该在C#3.0中查看extension methods。使用扩展方法将使您的Utilities更多地成为框架的“整体”部分,这似乎是您尝试通过考虑使它们变得抽象而做的。更不用说扩展方法了很多乐趣!

答案 9 :(得分:0)

有人提到在C#3.0中你可以通过扩展方法实现这一点。我不是C#的家伙,在1.5 / 2.0天内做了一些回复,但从那时起就没有用过它。基于粗略的理解,我认为在静态导入的java中可以实现类似的东西。我意识到它根本不是同一个东西,但如果目标只是让这些实用程序方法对调用类看起来更像“原生”(缺乏更好的术语),我认为它会起作用。假设我在原始问题中声明了Utilities类。

import static Utilities.getSomeData;

public class Consumer {

    public void doSomething(){

        String data =  getSomeData();
    }

}

答案 10 :(得分:0)

我可以提供一些建设性的建议吗?

如果你做了很多这样的事情,你会遇到两个问题。

首先,采用参数的静态方法通常应该是该参数的对象的一部分。我意识到这对像String这样的对象没有帮助,但是如果它需要你定义的对象,你几乎可以肯定通过将你的帮助器作为该对象的方法来改进对象。

如果它获取所有原生值,您可能可以定义一个它是方法的对象。查看是否可以找到这些本机值的任何分组并将它们分组为对象。如果你只是尝试一下,你会发现这个小迷你物体的许多其他用途,在你知道之前它会非常有用。

另一件事,如果你有一个带有一堆半相关静态方法和静态变量的实用程序类,你几乎总是希望它是一个单例。我通过反复试验找到了这个,但是当你发现你需要超过1(最终你会)时,将单例变成多个(?)然后尝试将静态类更改为多个(更容易)好的,所以我现在正在说话。)

祝你好运。这个东西对我来说大部分都是反复试验的 - 虽然它已经像5年前一样出现了,而且我从来没有找到一个让我后悔没有静态类/方法的实例。