Відповідь нижче неправильна, але я буду тримати її для того, щоб інші дізналися від неї (див. Нижче)
У 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 є неправильним:
Я мушу визнати, що про взірці Сінглтона я дізнався лише вчора (читаючи голову Першої книги дизайнерських моделей). Наївно я пішов і застосував це для цього прикладу, але, як багато хто вказував, один із способів - інший (деякі були більш кричущими і казали лише "ти робиш це неправильно!"), Це не дуже гарна ідея. Отже, щоб не допустити інших помилок, які я щойно робив, тут викладено короткий опис того, чому шаблон Singleton може бути шкідливим (на основі коментарів та того, що я виявив, що його гуглить):
Якщо ExampleA
отримає власне посилання на Config
екземпляр, класи будуть щільно з'єднані. Не буде можливості мати примірник ExampleA
використання іншої версії Config
(скажімо, підкласу). Це жахливо, якщо ви хочете протестувати ExampleA
за допомогою макетного екземпляра, Config
оскільки це не існує для цього ExampleA
.
Передумова існуватиме один, і лише один, екземпляр, Config
можливо, зараз є , але ви не завжди можете бути впевнені, що те саме відбудеться і в майбутньому . Якщо в якийсь пізній момент виявиться, що Config
бажано декілька екземплярів , немає можливості досягти цього, не переписавши код.
Незважаючи на те, що один-єдиний екземпляр Config
, можливо, правдивий на всю вічність, може статися так, що ви хочете мати можливість використовувати якийсь підклас Config
(при цьому, маючи лише один примірник). Але, так як код безпосередньо отримує екземпляр через getInstance()
з Config
, який являє собою static
метод, немає ніякого способу , щоб отримати підклас. Знову код потрібно переписати.
Те, що ExampleA
використовує, Config
буде приховано, принаймні, лише переглядаючи API ExampleA
. Це може бути або не бути поганою справою, але особисто я відчуваю, що це відчуває себе недоліком; наприклад, при підтримці не існує простого способу з’ясувати, на які класи впливатимуть зміни, Config
не вивчаючи впровадження будь-якого іншого класу.
Навіть якщо факт ExampleA
використання Singleton Config
сам по собі не є проблемою, він все ж може стати проблемою з точки зору тестування. Об'єкти Singleton матимуть стан, який зберігатиметься до припинення роботи програми. Це може бути проблемою при запуску одиничних тестів, оскільки ви хочете, щоб один тест був ізольований від іншого (тобто те, що виконавши один тест, не повинно впливати на результат іншого). Щоб виправити це, об'єкт Singleton повинен бути знищений між кожним тестовим запуском (можливо, доведеться перезапустити всю програму), що може зайняти багато часу (не кажучи вже про стомлювальний і дратівливий).
Сказавши це, я радий, що я допустив цю помилку тут, а не в реалізації реальної заявки. Насправді я фактично розглядав можливість переписати свій останній код, щоб використовувати шаблон Singleton для деяких класів. Хоча я міг би відновити зміни (звичайно, все зберігається у SVN), я все одно витратив би час на це.