Helper / Utility Classes应该是抽象的吗?
-
08-07-2019 - |
题
我经常发现自己将类中的常见行为提取到helper / utility类中,这些类只包含一组静态方法。我经常想知道我是否应该将这些类声明为抽象类,因为我无法真正想到实例化这些类的正当理由?
优点和缺点是宣布这样一个类是抽象的。
public [abstract] class Utilities{
public static String getSomeData(){
return "someData";
}
public static void doSomethingToObject(Object arg0){
}
}
解决方案
你可以声明一个什么都不做的私有构造函数。
声明类<!>“abstract <!>”的问题是抽象关键字通常意味着该类旨在进行子类化和扩展。这绝对不是你想要的。
其他提示
不要打扰它们是抽象的,而是包含一个私有的无参数构造函数来防止它们被实例化。
感兴趣的人的比较点:在C#中你会声明这个类是静态的,使它在编译形式中抽象为和密封(Java的最终版),而根本没有任何实例构造函数。这也使得声明该类型的参数,变量,数组等成为编译时错误。方便。
我没有声明实用程序类abstract,我将它们声明为final并使构造函数为private。这样它们就不能被子类化,也无法实例化。
public final class Utility
{
private Utility(){}
public static void doSomethingUseful()
{
...
}
}
通过将它们声明为抽象,您实际上向其他编码器指示您打算从这些类派生。真的,你是对的,没有太大区别,但这里的语义更多的是关于其他看你代码的人的解释。
我会在私有构造函数之外添加更多步骤:
public class Foo {
// non-instantiable class
private Foo() { throw new AssertionError(); }
}
抛出AssertionError
会阻止同一个类中的方法实例化类(好吧,他们可以尝试)。这通常不是问题,但在团队环境中,你永远不会知道某人会做什么。
关于<!> quot; abstract <!> quot;关键字,我注意到在很多实例中子类化的实用程序类:
public class CoreUtils { ... }
public class WebUtils extends CoreUtils { ... }
public class Foo { ... WebUtils.someMethodInCoreUtils() ... }
我相信这样做是为了让人们不必记住要包含哪个实用程序类。这有什么缺点吗?这是一种反模式吗?
此致 LES
正如其他人所说,建立一个私有的无参数构造函数。除了类本身之外,没有人可以创建它的实例。
正如其他人已经展示了如何使用其他语言,以下是如何在下一个C ++版本中执行此操作,如何使类不可实例化:
struct Utility {
static void doSomething() { /* ... */ }
Utility() = delete;
};
不,但是如果你的语言支持它,那就有一个强有力的论据,在大多数情况下它们应该(可以)被声明为'静态'...静态告诉编译器它们不能被实例化,并且所有它们中的方法必须是静态的。
Abstract是针对具有基于实例的实现细节的类,将由派生类的实例使用...
import static Utilities.getSomeData;
public class Consumer {
public void doSomething(){
String data = getSomeData();
}
}
我可以提供一些建设性的建议吗?
如果你做了很多这样的事情,你会遇到两个问题。
首先,采用参数的静态方法通常应该是该参数的对象的一部分。我意识到这对像String这样的对象没有帮助,但是如果它需要你定义的对象,你几乎可以肯定通过将你的帮助器作为该对象的方法来改进对象。
如果它获取所有原生值,您可能可以定义一个它是方法的对象。查看是否可以找到这些本机值的任何分组并将它们分组为对象。如果你只是尝试一下,你会发现这个小迷你物体的许多其他用途,在你知道之前它会非常有用。
另一件事,如果你有一个带有一堆半相关静态方法和静态变量的实用程序类,你几乎总是希望它是一个单例。我通过反复试验找到了这个,但当你发现你需要超过1(最终你会)时,将单例变成多个(?)然后尝试将静态类更改为多个(更容易)好的,所以我现在正在说话。)
祝你好运。这个东西对我来说大部分都是反复试验的 - 虽然它已经像5年前一样出现了,但是我从来没有找到一个让我后悔没有静态类/方法的实例。Helper / Utility方法很好。不要担心将它们添加到应用程序或框架内的库中。我见过的大多数框架都使用它们。
话虽如此,如果你想对他们变得非常狡猾,你应该看看扩展方法。使用扩展方法将使您的Utilities更多地使用<!> quot;整体<!>;你的框架的一部分似乎是你试图通过考虑使它们抽象而做的。更不用说扩展方法了很多乐趣!