0

Должны ли классы-помощники/утилиты быть абстрактными?

10

Я часто сталкиваюсь с необходимостью извлекать общие поведения из классов в вспомогательные или утилитарные классы, которые содержат только набор статических методов. У меня возникал вопрос: следует ли объявлять такие классы абстрактными, поскольку у меня нет какой-либо разумной причины для их инстанцирования?

Каковы будут плюсы и минусы объявления такого класса абстрактным?

public [abstract] class Utilities {

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

   public static void doSomethingToObject(Object arg0) {
   }
}

5 ответ(ов)

0

Вы можете просто объявить приватный конструктор, который ничего не делает.

Проблема с объявлением класса "абстрактным" заключается в том, что ключевое слово abstract обычно указывает на то, что класс предназначен для наследования и расширения. Это совсем не то, что вам нужно в данном случае.

0

Не стоит забивать себе голову абстракцией, но обязательно добавьте закрытый конструктор без параметров, чтобы предотвратить возможность инстанцирования класса.

Для тех, кто интересуется: в C# вы бы объявили класс статическим, что делает его абстрактным и запечатанным (как final в Java) в скомпилированной версии, и при этом без конструктора экземпляра вовсе. Это также приводит к ошибке компиляции при попытке объявить параметр, переменную, массив и т.д. этого типа. Удобно.

0

Вместо того чтобы объявлять утилитарные классы абстрактными, я предпочитаю объявлять их финальными и делать конструктор приватным. Таким образом, их нельзя будет наследовать или создавать экземпляры.

Вот пример такого класса:

public final class Utility
{
    private Utility(){}

    public static void doSomethingUseful()
    {
        // Реализация полезной функции
    }
}

Этот подход гарантирует, что класс используется только как контейнер для статических методов, что и является его основной целью.

0

В ответ на ваш вопрос, действительно, использование приватного конструктора — это хороший шаг к предотвращению инстанцирования классов-утилит. Ваш код, представляющий класс Foo, выглядит следующим образом:

public class Foo {
   // Класс не может быть инстанцирован
   private Foo() { throw new AssertionError(); }
}

Бросание AssertionError действительно предотвращает инстанцирование класса методами внутри него, хотя они могут попытаться это сделать. В обычной ситуации это не создает проблем, но в команде вы никогда не знаете, что может сделать кто-то другой.

Что касается использования ключевого слова "abstract", я замечал случаи, когда классы утилит наследуются:

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

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

Это делается для того, чтобы пользователям не приходилось запоминать, какой класс утилит включить. Однако, такой подход может иметь свои недостатки. Например, это может вызвать путаницу в иерархии классов и усложнить поддержку кода, поскольку разделение утилит по классам может быть не всегда интуитивным. Кроме того, непонятно, какая именно функциональность доступна в каждом из классов, если они не документированы должным образом.

Таким образом, можно сказать, что такой подход может являться антипаттерном. Лучше использовать статические методы в классах утилит без необходимости их наследования. Это делает код более понятным и предсказуемым для других разработчиков.

С уважением, LES

0

Объявляя классы абстрактными, вы фактически указываете другим разработчикам, что намерены, чтобы от этих классов наследовались другие. Действительно, вы правы, что между обычными классами и абстрактными нет большой разницы, но семантика здесь заключается именно в интерпретации вашего кода другими людьми.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь