2011-12-22 5 views
7

Мне нужно создать одноэлементный класс без сохранения статического метода.Создание одноэлементного класса без использования статического метода

Как я могу это сделать?

+0

Только вызовите конструктор один раз. –

+0

Использовать статическую переменную? – dasblinkenlight

+2

@M Platvoet - Это не синглтон, потому что вы можете вызвать конструктор во второй раз. –

ответ

19

Создайте перечисление с одним экземпляром

enum Singleton { 
    INSTANCE; 

    private Field field = VALUE; 
    public Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Singleton.INSTANCE.method(arg); 

EDIT: Java Enum Tutorial показывает вам, как добавить поля и методы перечисления.


КСТАТИ: Часто, когда вы можете использовать Singleton, вы на самом деле не нужен один, как служебный класс будет делать то же самое. Еще более короткая версия - это только

enum Utility {; 
    private static Field field = VALUE; 
    public static Value method(Arg arg) { /* some code */ } 
} 

// You can use 
Value v = Utility.method(arg); 

Где синглтоны полезны, когда они реализуют интерфейс. Это особенно полезно для тестирования при использовании инъекции зависимостей. (Одна из слабостей использования замены Singleton или замены полезного класса в модульных тестах)

, например.

interface TimeService { 
    public long currentTimeMS(); 
} 

// used when running the program in production. 
enum VanillaTimeService implements TimeService { 
    INSTANCE; 
    public long currentTimeMS() { return System.currentTimeMS(); } 
} 

// used in testing. 
class FixedTimeService implements TimeService { 
    private long currentTimeMS = 0; 
    public void currentTimeMS(long currentTimeMS) { this.currentTimeMS = currentTimeMS; } 
    public long currentTimeMS() { return currentTimeMS; } 
} 

Как вы можете видеть, если ваш код использует TimeService везде, вы можете вводить либо VanillaTimeService.INSTANCE или new FixedTimeService(), где вы можете контролировать время снаружи, т.е. ваши временные метки будут такими же, каждый раз, когда вы запускаете тест.

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

+0

@Pater Спасибо за быстрый ответ –

+0

Я не понимаю ... вы не можете вызвать какой-либо метод на вашем одиночном телефоне –

+0

@remi bourgarel java enum - это просто класс. Просто добавьте переменные, методы и конструктор в перечисление Singleton (после объявления INSTANCE), как это было бы с любым другим классом, а INSTANCE - с ними. – josefx

1

Следуйте рецепту перечисления Джошуа Блоха в «Эффективной Java» 2-го издания. Это лучший способ создать синглтон.

Я не понимаю, почему это так много. Не является ли одиночный диск дискредитированным шаблоном проектирования? Сегодня GoF будет голосовать за него.

1

Вы можете использовать один из контейнеров IoC (например, Google Guice) и использовать свой класс как singleton (нетерпеливый или ленивый - это зависит от ваших потребностей). Это легко и гибко, поскольку создание экземпляров контролируется каркасом IoC - вам не нужны какие-либо изменения кода, если, например, вы решите сделать свой класс не singleton позже.

+0

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

+0

Почему? IoC сейчас довольно обычная вещь. И это плюс, если собеседник знает об этом и предлагает использовать IoC framework как одно из возможных решений. – Artem

+0

Да, сейчас IoC является общим knowlegde. Безусловно, он не используется во всех проектах. Поэтому, если интервьюер не проявил интереса к какой-либо структуре IoC раньше, _I_ предположил бы, что вопрос хочет проверить знание самого языка. Если вы не показываете, что знаете, как простые вещи можно сделать простым способом, но только сложным способом с участием нескольких тяжелых фреймворков, то можно предположить, что ваши обычные навыки решения проблем работают одинаково.
Лучшее, что нужно сделать: показать оба решения. –

8
public class Singleton { 
    public static final Singleton instance = new Singleton(); 
    private Singleton() {} 
    public void foo() {} 
} 

затем использовать

Singleton.instance.foo(); 
+1

Для полноты: добавьте частный конструктор no-arg. –

+0

Отлично! Спасибо, А.Х.! (Моя обычная ошибка :) – andrey

0

Используйте объектную фабрику, принесите свою одноплодную объект из этого завода.

ObjectFactory factory; 
.... 
MySingletonObject obj = factory.getInstance(MySingletonObject.class); 

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

+0

Не работает ли какой-либо статический метод? Этого он не хочет. – Eduard

0

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

2

Другим подходом является singleton holder idiom, который предлагает инициализацию по требованию:

public class Something { 
     private Something() { 
     } 

     private static class LazyHolder { 
       public static final Something INSTANCE = new Something(); 
     } 

     public Something getInstance() { 
       return LazyHolder.INSTANCE; 
     } 
} 

(пример модифицированного, изготовленный методом GetInstance не статический)

Обратите внимание, что автономные одноэлементные, как это следует избегать, где это возможно, потому что он способствует глобальное состояние, приводит к жесткому для unittest коду и зависит от одного контекста загрузчика классов, чтобы назвать несколько возможных недостатков.

Смежные вопросы