我通常会发现自己将类的常见行为提取到帮助程序/实用程序类中,该类只包含一组静态方法。 我经常想知道是否应该将这些类声明为抽象类,因为我真的想不出实例化这些类的有效理由吗?
将这样的类声明为抽象将是什么利弊。
public [abstract] class Utilities{
public static String getSomeData(){
return"someData";
}
public static void doSomethingToObject(Object arg0){
}
}
您可以声明一个不执行任何操作的私有构造函数。
声明类"抽象"的问题在于abstract关键字通常意味着该类打算被子类化和扩展。那绝对不是你想要的。
并可能将其声明为最终声明,以使您的意图绝对清晰。
可悲的是,您不能将其声明为抽象的final。 :-)
他没有暗示他应该...:|
不要打扰让它们成为抽象,而是包括一个私有的无参数构造函数,以防止它们被实例化。
感兴趣的人的比较点:在C#中,您将声明该类为静态类,使其以编译形式抽象和密封(Java的最终版本),并且完全没有任何实例构造函数。这也使得声明该类型的参数,变量,数组等成为编译时错误。便利。
我没有将实用程序类声明为抽象,而是将它们声明为final并使构造函数私有。这样,它们就不能被子类化,也不能被实例化。
public final class Utility
{
private Utility(){}
public static void doSomethingUseful()
{
...
}
}
使用上面建议的这种格式,我是否应该使用"静态导入"行来导入要在我的项目中使用的类方法?
我将在私有构造函数之外添加更多步骤:
public class Foo {
// non-instantiable class
private Foo() { throw new AssertionError(); }
}
抛出AssertionError可以防止同一类中的方法实例化该类(可以尝试)。这通常不是问题,但是在团队环境中,您永远都不知道有人会做什么。
关于"抽象"关键字,我注意到在许多情况下子类化的实用程序类:
public class CoreUtils { ... }
public class WebUtils extends CoreUtils { ... }
public class Foo { ... WebUtils.someMethodInCoreUtils() ... }
我相信这样做是为了使人们不必记住要包括哪个实用程序类。这有什么缺点吗?这是反模式吗?
问候,
莱斯
通过将它们声明为抽象,实际上是在向其他编码器指示您打算从中继承这些类。确实,您是对的,没有太大的区别,但是这里的语义实际上更多地是关于其他查看您的代码的人的解释。
如其他人所述,创建一个私有的无参数构造函数。除了类本身之外,没有人可以创建它的实例。
正如其他人展示了如何用其他语言完成操作一样,下面是您在下一个C ++版本中的操作方法,以及如何使类不可实例化的方法:
struct Utility {
static void doSomething() { /* ... */ }
Utility() = delete;
};
我认为最好使用私有的无参数构造函数将实用程序类声明为final。此外,此类的所有成员都应该是静态的。
在一个语句中完成所有这些操作的一种简单方法是使用Lombok的@UtilityClass批注:
@UtilityClass
public class Utilities{
public String getSomeData() {
return"someData";
}
public void doSomethingToObject(Object arg0) {
}
}
如果使用@UtilityClass批注,则可以跳过上面的示例中的静态关键字,因为Lombok在编译过程中会自动添加它们。
我可以提供一些建设性的建议吗?
如果您要执行很多操作,则会遇到两个问题。
首先,带有参数的静态方法通常应该是该参数的对象的一部分。我意识到这对像String这样的对象没有帮助,但是如果它接受您已定义的对象,则几乎可以肯定的是,可以通过将助手作为该对象的方法包括在内来改进该对象。
如果它采用所有本机值,则可能可以定义一个作为其方法的对象。看看是否可以找到这些原始值的任何分组并将它们分组为一个对象。如果您只是尝试一下,您会发现该小物件还有很多其他用途,并且在您不知道它会非常有用的情况下。
另一件事,如果您有一个带有一堆半相关的静态方法和静态变量的实用程序类,则几乎总是希望它成为单例。我通过反复试验发现了这一点,但是当您发现需要多个(最终会需要)时,将单例转换为multipleton(?),然后尝试将静态类更改为multipleton((好的,所以我现在要说些什么)。
祝好运。这些东西对我来说大多是试验和错误的-尽管将它弄成5年前的样子,但我从未发现我后悔没有静态类/方法的实例。
有人提到在C#3.0中,您可以通过扩展方法来完成此任务。我不是C#的人,在1.5 / 2.0天内做了一些工作,但是从那时起就没有使用过。基于非常粗略的理解,我认为使用静态导入在Java中可以完成类似的操作。我意识到它根本不是一回事,但是如果目标是使这些实用程序方法对调用类来说看起来更"本机"(因为缺少更好的术语),我认为它将成功。假设我在原始问题中声明了Utilities类。
import static Utilities.getSomeData;
public class Consumer {
public void doSomething(){
String data = getSomeData();
}
}
这是有效的Java吗?
Helper / Utility方法很好。不必担心将它们添加到应用程序或Framework内部的库中。我见过的大多数框架都在许多方面使用它们。
话虽如此,如果您想真正地对它们有所了解,就应该研究C#3.0中的扩展方法。使用扩展方法将使您的实用程序更像是框架的"整体"部分,这似乎是您正在考虑通过使其抽象化来尝试做的事情。更不用说扩展方法了,写起来很有趣!
不,但是如果您的语言支持,则有一个很强的论点,即在大多数情况下,它们应该(可以)声明为"静态" ...静态告诉编译器无法实例化它们,并且其中的所有方法必须是静态的。
抽象用于确实具有基于实例的实现细节的类,派生类的实例将使用这些细节...
java类不能声明为静态,可以吗? 也许我只是误解了您的观点?
抱歉,Im .Net家伙...并没有注意到java标记...然后,如果无法将java类声明为静态,则应将私有无参数ctor设置为静态,并将所有成员设置为静态...
在某些情况下,可以将Java类声明为静态类,但这意味着有所不同。