Ниже приведен неправильный ответ, но я оставлю его для изучения другими (см. Ниже)
В ExampleA
, вы можете использовать один и тот же Config
экземпляр для нескольких классов. Однако, если Config
во всем приложении должен быть только один экземпляр, рассмотрите возможность применения шаблона Singleton, Config
чтобы избежать нескольких экземпляров Config
. И если Config
это Singleton, вы можете сделать следующее:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
В ExampleB
, с другой стороны, вы всегда получите отдельный экземпляр Config
для каждого экземпляра ExampleB
.
Какую версию вы должны применить, зависит от того, как приложение будет обрабатывать случаи Config
:
- если каждый экземпляр
ExampleX
должен иметь отдельный экземпляр Config
, переходите к ExampleB
;
- если каждый экземпляр
ExampleX
разделяет один (и только один) экземпляр Config
, используйте ExampleA with Config Singleton
;
- если экземпляры
ExampleX
могут использовать разные экземпляры Config
, придерживайтесь ExampleA
.
Почему преобразование Config
в синглтон неправильно:
Я должен признать, что я узнал о паттерне Singleton только вчера (читая книгу « First First», посвященную шаблонам проектирования). Наивно я пошел и применил его для этого примера, но, как многие отмечали, один путь - другой (некоторые были более загадочными и говорили только: «Вы делаете это неправильно!»), Это не очень хорошая идея. Итак, чтобы не допустить повторения той же ошибки, которую я только что совершил, ниже приведено краткое изложение причин, по которым паттерн Синглтон может быть вредным (на основе комментариев и того, что я обнаружил, погугляя)
Если ExampleA
получить собственную ссылку на Config
экземпляр, классы будут тесно связаны. Не будет никакого способа иметь экземпляр ExampleA
для использования другой версии Config
(скажем, некоторого подкласса). Это ужасно, если вы хотите протестировать ExampleA
с использованием экземпляра макета, Config
поскольку нет способа предоставить его ExampleA
.
Предположение о том, что будет один, и только один, Config
может быть, имеет место сейчас , но вы не всегда можете быть уверены, что то же самое сохранится в будущем . Если в какой-то более поздний момент окажется, что несколько экземпляров Config
будут желательны, нет способа достичь этого без переписывания кода.
Даже если один-единственный-единственный экземпляр Config
может быть верным на всю вечность, может случиться так, что вы захотите использовать некоторый подкласс Config
(хотя при этом у вас будет только один экземпляр). Но, поскольку код напрямую получает экземпляр с помощью getInstance()
of Config
, который является static
методом, нет способа получить подкласс. Опять же, код должен быть переписан.
Тот факт, что ExampleA
использует, Config
будет скрыт, по крайней мере, при просмотре только API ExampleA
. Это может или не может быть плохой вещью, но лично я чувствую, что это чувствует себя недостатком; например, при ведении не существует простого способа выяснить, на какие классы будут влиять изменения, Config
не рассматривая реализацию любого другого класса.
Даже если сам факт ExampleA
использования Singleton Config
не является проблемой сам по себе, он все равно может стать проблемой с точки зрения тестирования. Одиночные объекты будут нести состояние, которое будет сохраняться до завершения приложения. Это может быть проблемой при запуске модульных тестов, поскольку вы хотите, чтобы один тест был изолирован от другого (то есть выполнение одного теста не должно влиять на результат другого). Чтобы исправить это, объект Singleton должен быть уничтожен между каждым запуском теста (возможно, потребуется перезапустить все приложение), что может занять много времени (не говоря уже об утомительном и раздражающем).
Сказав это, я рад, что я сделал эту ошибку здесь, а не в реализации реального приложения. На самом деле, я подумывал переписать свой последний код, чтобы использовать шаблон Singleton для некоторых классов. Хотя я мог бы легко отменить изменения (все хранится в SVN, конечно), я все равно потратил бы впустую время, делая это.