Ты узнаешь это:

public class X {
	private static X instance = null;

	private X() {}

	public static X instance() {
		if (instance == null)
			instance = new X();
		return instance;
	}

	// more methods...
}

Конечно. Это паттерн Singleton (Одиночка) из книги банды четырех. Я всегда слышал, что мы не должны использовать его.

Почему мы не должны использовать его?

Потому, что это делает наши системы трудно тестируемыми.

Это делает? Почему?

Потому, что мы не можем замокать наш синглтон.

Вы не можете? Почему?

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

Ты знаешь правило о инкапсуляции и тестах?

Мм, нет. Какое правило?

Тесты выше инкапсуляции.

Что это значит?

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

Вы имеете ввиду - если тесту нужен доступ к приватной переменной…

…переменная не должна быть приватной. Да.

Просто это звучит неправильно. Я имею в виду, инкапсуляция важна!

Тесты более важны.

Погодите. Что?

Что хорошего в инкапсулированном коде, если вы не можете его протестировать?

Хорошо, хорошо, но какое это имеет отношение к тестированию синглтонов.

Посмотрите на этот код.

public class X {
	static X instance = null;

	private X() {}

	public static X instance() {
		if (instance == null)
			instance = new X();
		return instance;
	}

	// methods.
}

class TestX {
	@Before
	public setup() {
		X.instance = new XMock();
	}
}

class XMock extends X {
	// overide methods
}

О, вы сделали переменную instance доступной в контексте “пакета”.

Верно

И это позволяет Вам замокать синглтон.

Верно.

И это означает, что синглтон можно просто мокать.

Верно. Теперь посмотрим на это:

public class X {
	public static X instance = new X();

	private X() {}

	// methods.
}

Подождите! А куда делся метод instance?

Мне он не нужен.

Ааа, переменная instance публичная. Вы можете просто использовать ее.

Верно.

Но… Но… Кто-то может перезаписать ее?

Кто это может сделать?

Я не знаю. Эмм. Кто-то плохой.

В вашей команде есть плохие люди?

Нет. Но. Так не чувствуешь себя в безопастности.

Ну, если бы это было частью общедоступного API, то я согласился бы с Вами. Но если это - просто код, который используется нашей командой тогда…

Мы доверяем нашей команде?

Конечно.

И это довольно просто замокать, не так ли?

Конечно.

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

Конечно. Хотя большую часть времени я не хочу.

В конце концов, это… и теперь Вы говорите, что не хотите использовать синглтон в любом случае?

Ну… я думаю, что важно понять для чего.

Хорошо, так почему бы тебе не использовать синглтон?

Иногда я использую. Особенно в публичных API.

Вы имеете в виду что это снова вопрос доверия?

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

Хорошо, но тогда что, если это не публичное API, но Вы все еще просто хотите создать один экземпляр?

Ну, тогда я просто создаю один.


Robert Martin (Uncle Bob)

Оригинал

Теги: паттерны, тестирование, перевод