Как реализовать почти синглтон? - PullRequest
5 голосов
/ 23 декабря 2010

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

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

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

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

Вот что я делаю:

/**
 * The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
 * "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
 * document are to be interpreted as described in RFC 2119.
 *
 * You MUST NOT instantiate this class more than once during the application's
 * lifecycle.  If you try to do so, an exception SHALL be thrown.
 *
 * You SHOULD be able to instantiate this class more than once when unit
 * testing.
 *
 * 
 */
public class LifeCycle {

    private static final AtomicInteger cnt = new AtomicInteger( 0 );

    @NotNull
    public static LifeCycle getNewLifeCycle() {
        if ( cnt.incrementAndGet() > 1 && App.isRealApp() ) {
            throw new IllegalStateException("Class is already instantiated");
        }
        return new LifeCycle();
    }

}

, где App.isRealApp () всегда должен возвращать false когда я тестирую модули и всегда true когда работает настоящее приложение.

Мой вопрос прост: делает ли онсмысл и как мне это реализовать?

Ответы [ 3 ]

9 голосов
/ 23 декабря 2010

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

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

Прокси-сервер не должен иметь никакой логики - он должен просто сопоставлять вызовы с синглтоном.

Затем вы можете использовать его в тестах и ​​оставить кодовую базу с синглтоном без изменений.Облегченный прокси-сервер может оставаться частью пакета тестирования и не может быть выпущен.

5 голосов
/ 23 декабря 2010

Одним из решений является использование инфраструктуры внедрения зависимостей, такой как Spring.

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

Для получения дополнительной информации: http://static.springsource.org/spring/docs/2.5.x/reference/testing.html

Альтернативой, если у вас уже есть статические одноэлементные ссылки, разбросанные по всему коду, является преобразование вашего Singleton.getInstance() метода в настоящую фабрику, используя системное свойство для управления его поведением. Это системное свойство может быть таким же простым, как флаг, чтобы указать, что тестирование находится в процессе, или таким же сложным, как имя другого класса для использования в качестве реальной фабрики (аналогично тому, что JDK делает с DocumentBuilderFactory).

0 голосов
/ 30 апреля 2011

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

Это то, что предписывает Singleton.

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

Вы можете принудительно применить это с @com.dp4j.Singleton

Это то, что позволяет API Reflection.

Вы можете либо напрямую использовать API Reflection, либо использовать dp4j для вас. Здесь вы найдете код для обоих.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...