Избегайте создания экземпляров класса в Java
Недавно я столкнулся с вопросом: как избежать создания экземпляров Java-класса?
Однако я ответил, сказав:
Если вы не хотите создавать экземпляр класса, используйте модификатор "abstract". Пример: javax.servlet.HttpServlet, объявляется как абстрактный (хотя ни один из его методов не является абстрактным), чтобы избежать создания экземпляров.
Объявите частный конструктор без аргументов.
Теперь мой вопрос а) есть ли другие способы? б) почему никто не хочет создавать экземпляр класса? - после поиска в SO я узнал, что классы Util могут быть созданы не для создания экземпляров. Какие-нибудь другие места, где мы не хотим создавать экземпляр класса в ООП?
5 ответов
На ум приходят четыре причины:
- Разрешить создание экземпляров подклассов, но не родительских;
- Запретить непосредственное создание экземпляров и вместо этого предоставлять фабричный метод для возврата и, если необходимо, создавать экземпляры;
- Поскольку все экземпляры предопределены (например, подходит для колоды карт), хотя, начиная с Java 5, вместо них рекомендуются безопасные перечисления типов; а также
- Класс действительно не класс. Это просто держатель для статических констант и / или методов.
В качестве примера (2) вы можете создать канонические объекты. Например, цветовые комбинации RGB. Вы не хотите создавать более одного экземпляра любой комбинации RGB, поэтому вы делаете это:
public class MyColor {
private final int red, green, blue;
private MyColor(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public static MyColor getInstance(int red, int green, int blue) {
// if combo already exists, return it, otherwise create new instance
}
}
Примечание: конструктор без аргументов не требуется, потому что явно задан другой конструктор.
Не совсем ответ на ваш вопрос, а просто примечание:
Когда вы создаете частный конструктор без аргументов, чтобы предотвратить создание экземпляров ваших служебных классов, вы должны заставить конструктор выдать исключение (например, UnsupportedOperationException). Это потому, что вы можете получить доступ к закрытым членам (включая конструкторы) через рефлексию. Обратите внимание, что если вы это сделаете, вы должны сопровождать его комментарием, потому что это немного нелогично, что вы определяете конструктор, чтобы предотвратить создание экземпляра класса.
Делать вспомогательный класс абстрактным не очень хорошая идея, потому что он делает класс таким, как будто он предназначен для расширения, и, кроме того, вы можете расширить класс и, таким образом, создать его экземпляр.
Иногда вам нужно только избегать создания экземпляров ваших объектов другими пользователями, чтобы иметь полный контроль над всеми существующими экземплярами. Одним из примеров является шаблон синглтона.
Я думаю, что наиболее распространенная причина отказа от создания экземпляра класса - это когда вы имеете дело со статическим классом и, следовательно, с его статическими методами. Вы не хотите, чтобы кто-то пытался создать экземпляр этого класса. Аналогично, когда вы имеете дело с классами Factory или в некоторых случаях многие одноэлементные классы скрывают свой конструктор, чтобы его нельзя было создать обычным образом.
Еще один способ сделать класс неинстанцируемым - это объявить его как закрытый внутренний класс, а затем не предоставлять какой-либо способ его создания в окружающем классе. Но это (ИМО) довольно бессмысленно.
Вы хотите, чтобы класс был неинстанцируемым, если нет смысла его создавать. Обычно вы делаете это, если класс на самом деле является просто набором (статических) вспомогательных методов или если класс является "неполным". Неполнота может быть синтаксически очевидна (то есть абстрактные методы), но есть и другие виды неполноты. Например, вы можете предоставить стандартные реализации по умолчанию для всех методов и требовать, чтобы один или несколько из них были переопределены, чтобы класс сделал что-то полезное.
Еще одна причина сделать класс неинстанцируемым (или, по крайней мере, напрямую не инстанцируемым), если ваше приложение должно управлять инстанцированием. Например, класс java.util.regex.Pattern не может быть создан напрямую, поэтому JRE может (может) поддерживать кэш предварительно скомпилированных регулярных выражений.