Должны ли вспомогательные / служебные классы быть абстрактными? - PullRequest
45 голосов
/ 21 ноября 2008

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

Что за и против было бы объявлением такого класса абстрактным.

public [abstract] class Utilities{

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

   public static void doSomethingToObject(Object arg0){
   }
}

Ответы [ 10 ]

71 голосов
/ 21 ноября 2008

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

Проблема с объявлением класса «абстрактный» заключается в том, что ключевое слово abstract обычно означает, что класс предназначен для создания подклассов и расширений. Это определенно не то, что вы хотите здесь.

18 голосов
/ 21 ноября 2008

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

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

9 голосов
/ 22 ноября 2008

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



public final class Utility
{
    private Utility(){}

    public static void doSomethingUseful()
    {
        ...
    }
}
3 голосов
/ 29 января 2009

Я бы добавил еще шаг за пределы частного конструктора:

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

3 голосов
/ 21 ноября 2008

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

2 голосов
/ 22 ноября 2008

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

Как другие показали, как это делается с другими языками, вот как вы это сделаете в следующей версии C ++, как сделать класс неинстанцируемым:

struct Utility { 
    static void doSomething() { /* ... */ } 
    Utility() = delete; 
};
0 голосов
/ 30 января 2009

Могу ли я дать конструктивный совет?

Если вы многое делаете, есть две проблемы, с которыми вы столкнетесь.

Прежде всего, статический метод, который принимает параметр, часто должен быть частью объекта, который является этим параметром. Я понимаю, что это не помогает для таких объектов, как String, но если он принимает объекты, которые вы определили, вы почти наверняка можете улучшить объект, включив в него метод помощника.

Если он принимает все собственные значения, вы, вероятно, можете определить объект, для которого это метод. Посмотрите, сможете ли вы найти какую-либо группировку этих собственных значений и сгруппировать их как объект. Если вы просто попробуете это, вы найдете множество других применений для этого маленького мини-объекта, и, прежде чем вы это узнаете, он будет удивительно полезен.

Другое дело, если у вас есть служебный класс с набором полусвязанных статических методов и статических переменных, вы почти всегда хотите, чтобы он был одиночным. Я обнаружил это методом проб и ошибок, но когда вы обнаружите, что вам нужно больше 1 (в конечном итоге вы захотите), гораздо проще превратить синглтон в мультиплетон (?), Чем пытаться преобразовать статический класс в мультиплетон ( хорошо, так что я сейчас придумываю слова).

Удачи. Этот материал был для меня в основном методом проб и ошибок - хотя я это понял 5 лет назад, и я никогда не встречал случая, чтобы сожалеть о том, что у меня нет статического класса / методов.

0 голосов
/ 22 ноября 2008

кто-то упомянул, что в C # 3.0 это можно сделать с помощью методов расширения. Я не C # парень, сделал некоторые назад в 1,5 / 2,0 дней, но не использовал его с тех пор. Основываясь на очень поверхностном понимании, я думаю, что нечто подобное может быть достигнуто в Java с помощью статического импорта. Я понимаю, что это совсем не одно и то же, но если цель состоит в том, чтобы эти служебные методы казались немного более «родными» (из-за отсутствия лучшего термина) вызывающему классу, я думаю, что это поможет. Предполагая, что класс Utilities я объявил в своем первоначальном вопросе.

import static Utilities.getSomeData;

public class Consumer {

    public void doSomething(){

        String data =  getSomeData();
    }

}
0 голосов
/ 21 ноября 2008

Вспомогательные / служебные методы просто хороши. Не беспокойтесь о добавлении их в библиотеку внутри вашего приложения или платформы. Большинство каркасов, которые я видел, используют их во многих вариантах.

При этом, если вы хотите быть действительно хитрыми, вы должны изучить методы расширения в C # 3.0. Использование метода расширения сделает ваши утилиты немного более «целостными» частью вашей среды, что похоже на то, что вы пытаетесь сделать, подумав сделать их абстрактными. Не говоря уже о методе расширения, очень весело писать!

0 голосов
/ 21 ноября 2008

Нет, но если ваш язык поддерживает это, есть веский аргумент в пользу того, что в большинстве случаев они должны (могут) быть объявлены как «статические» ... Static сообщает компилятору, что их нельзя создать, и методы в них должны быть статичными.

Аннотация предназначена для классов, которые имеют детали реализации на основе экземпляров, которые будут использоваться экземплярами производных классов ...

...