Pull to refresh

Comments 83

По-моему, в последнее время создание статей на Хабре превратилось в создание ради создания =)
Почему же? При искреннем изложении материала, автор топика может привнести нечто своё, новое, под новым углом зрения; чем больше граней, под которыми смотрите на материал, тем больше информации для размышления у Вас будет. Тогда как строгий, целостный книжный стиль изложения, к которому не то, что не придерёшься, а всё так подогнано, что не за что зацепиться мыслью, может показаться сухим, и не очень успешно усваиваться. Как-то так.
Я бы рекомендовал её к прочтению тем, кто только начал осознавать, что его коду чего-то не хватает, и что он созрел для вникания в это далёкое понятие – «паттерны».

Вот это как раз самый опасный вариант. После него в коде везде появляются «паттерны», причем как там, где надо, так и там, где не надо.

(особенно когда статья сама (а) путает разные паттерны, и (б) не объясняет, зачем они, собственно, нужны)
Ну я сразу сказал, что конкретики не будет. Википедию никто не отменял. Там можно почитать, зачем паттерны нужны. Цели статьи были другими.
А вот за более раскрытые замечания был бы признателен. Где именно я перепутал разные паттерны?
Пул объектов это пул объектов и называть класс Fabric — вводит в заблуждение (фабрика порождает, но не хранит). Во-вторых, каноническая реализация пула объектов несколько иная. Отличия: мало того, что он хранит объекты, он же их и создает (благо, в PHP это вообще не трудно реализовать, но поскольку в php не нужно следить за ссылками на объект, в этом смысла особого нет. Он так то и придуман для того, чтобы не терять объекты, где нет сборщика мусора, и чтобы их не удалять и не создавать по многу раз, а постоянно хранить до завершения работы приложения). Вдобавок, пул сам по себе не должен быть статическим, а должен быть классом, от которого можно создавать объекты. А вот эти объекты уже можно обертывать в статические классы или синглтоны. Это по той причине, что для повышения производительности выборки и добавления объектов в пул, их может быть несколько (разбиты на логические группы, например, «товары», «пользователи», «комментарии»).

Кривая реализация одиночки.
Че вдруг деструктор закрыт? Да, скорее всего одиночка проживет все время существования приложения, но удалить её может понадобиться. Грамотнее было бы сделать примерно так: добавить переменную, которая обозначала бы, что объект больше не нужен, в деструкторе проверять её, и удалять соответственно.
Почему одиночку нельзя вдруг создавать через конструктор? Почему не перенести логику из function getInstance() в конструктор?

Ваша абстрактная фабрика вообще непонятно для чего нужна. Исправить эту досадную мелочь легко исправить, добавив второй вид создаваемых продуктов (getProductA(), getProductB())

Главное замечание ко всей статье — не понятно, зачем она нужна?
На чем, но на php реализация большинства паттернов элементарна и интуитивна. И давать лишь код этого, не описывая сами паттерны и случаи их применения — глупо. Уж лучше допишите их в ту же википедию в примеры, если хотите сделать что-то полезное, а не написать «статью ради статьи».
Про абстрактную фабрику я немного не прав, но ваш пример все равно не очень понятен, потому что сразу же возникает вопрос — почему мы напрямую не могли взять этот объект? Пример с той же википедии несколько нагляднее.

И да, глупо писать тут название паттерна, приводит пример реализации, но отправлять человека читать о самом паттерне на вики, где уже есть пример на этом же языке.
Почему одиночку нельзя вдруг создавать через конструктор? Почему не перенести логику из function getInstance() в конструктор?

Простите, это как? Конструктор в PHP (как и почти во всех ОО языках) не обладает блоком возврата.
Да неужели :)?

<?php
var_dump(new StdClass()); //returns: object(stdClass)#1 (0) { }
Сарказм неуместен. Вы же понимаете разницу между языковой конструкцией new и конструктором класса?
Тут нет сарказма. Насколько я в курсе в PHP конструктор класса вызывается с помощью оператора new и никак иначе его вызвать нельзя. И оператор new для других целей не применяется.

Но вообще, я не силен в ООП, могу и ошибаться.

Я ниже привел фрагмент кода. Давайте его обсудим, помогите разобраться.
Языковая конструкция new создает экземпляр объекта указанного класса. Вызов конструктора при этом является побочным действием и не влияют (кроме брошенного исключения) на поведение new, и как следствие интерпретатор PHP не учитывает блок возврата (return $something) в конструкторе.
Но вообще, я не силен в ООП, могу и ошибаться.

С этого и стоило бы начать. Для вопросов есть соответствующий сервис.
Да, что-то меня занесло, просто последние пол года пишу в основном на JS и немного на С (чистом), в первом так можно без проблем, во втором так нельзя в принципе.

Но если не брать случай, что именно объект должен быть уникальным и в единственном экземпляре, а не данные, с какими он работает, то это не сложно (он просто будет агрегировать статичные данные или ту же одиночку). А если брать, что именно объект должен быть уникальным — придется написать нехилый костыль.
Почему одиночку нельзя вдруг создавать через конструктор? Почему не перенести логику из function getInstance() в конструктор?

Потому что self() вызывает конструктор (а в этот момент он ещё не instanceof self — значит он ещё раз вызовет self(), который, в свою очередь, ещё раз вызовет self(), который...). Если содержимое getInstance() перенести в __construct(), то выполнение просто зациклится. Всё равно, что писать while(true){/*здесь нет никаких break, exit и т.п.*/}.
А переписывать код так, чтобы не было зацикливания, — тоже нет смысла; в __construct() нет смысла использовать return, потому что __construct() в любом случае возвращает новый экземпляр класса.
Ну, наверное, правильней сказать, что конструктор вообще ничего не возвращает… То, что мы помещаем в конструктор, вызывается после создания экземпляра класса.
Почему одиночку нельзя вдруг создавать через конструктор? Почему не перенести логику из function getInstance() в конструктор?

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

Какими?

Википедию никто не отменял. Там можно почитать, зачем паттерны нужны.

Так и GoF никто не отменял, там можно почитать и все остальное про паттерны.

Где именно я перепутал разные паттерны?

Реестр — не порождающий паттерн, и он здесь низачем не нужен.
Пул объектов — это не порождающий паттерн, он не является частным случаем реестра, и в него никогда не «складывают» объекты (они появляются там «магией»).
Что такое «пул одиночек» и зачем он нужен — непонятно.
Фабричный метод реализуется в том же классе, который им порождается (и, кстати, поэтому ваша реализация синглтона — это частный случай фабричного метода); а то, что у вас описано, как фабричный метод — это фабрика.
Чем отличается Lazy Initialization от Singleton в вашем описании?
Ваша реализация Builder ничем не отличается от фабрики, хотя на самом деле у них есть существенные отличия.
В примере 5, SecondFactory создает FirstProduct
Спасибо, не углядел. Исправил.
Нет самого популярного шаблона в списке — DI. Он частично порождающий.
Покажите DI на простом реалистичном примере, пожалуйста.
Там реализация… а мне не понятно, зачем это вообще.
А вам понятно, зачем нужен Inversion of Control?
Не очень.

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

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

Нет. В том смысле, что вообще нет.

IoC нужен для того, чтобы мы могли в любой момент заменить одну реализацию другой; а это, в свою очередь, нужно для тестирования и расширяемости приложения. Подробности — у Роберта Мартина.
А… в таком случае, в моем примере это есть.

$STATE["db"] = get_db_object();

Я понимаю, что для вас такой синтаксис не привычен. Здесь в свойство db объекта «Приложение» записывается объект «База данных», реализация которого может быть любой.

Ушел читать Мартина.
Есть-то есть (в какой-то части), только реализовано криво (вместо того, чтобы использовать Service Locator или Dependency Injection, вы изобретаете свой полувелосипед, похожий на SL, но существенно кривее).
Вы же понимаете, что когда вы меня ругаете: «криво», «ошибка», было бы полезно пояснить в чем именно кривизна…. Я-то этого не вижу, иначе бы так не сделал.

Либо же нет никакой кривизны, просто вы не понимаете мой код.

«Кривизна» в том, что (а) вы используете некий глобальный объект для хранения всей (т.е., несвязанной) информации; это т.н. god object, функции которого нельзя определить (б) вы используете строковые ключи вместо «нормальных» свойств или, еще лучше, типа сервиса в качестве ключа, (ц) вместо того, чтобы создавать зависимость в момент ее необходимости (причем — с нужным жизненным циклом), вы ее явно прописываете в этот глобальный объект и, наконец, (д) service locator вообще последнее время считается антипаттерном.
(а) В фреймворках часто можно встретить объект $app. Оттого, что я назвал его $STATE не делает его «кривым». В этой переменной хранится состояние приложения. Информация связана — вся она относится к приложению.
(б) Чем, по-вашему, "$obj->property" остроконечников лучше чем "$obj[«property»] тупоконечников?
Мне просто нравится такой синтаксис. Но можно заменить тип $STATE с array на StdClass и обращаться к его свойствам, используя объектную нотацию.

(ц), (д) — тут прошу поподробнее. Чувствую ценность в вашем комментарии, но нужно больше деталей.
В фреймворках часто можно встретить объект $app

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

Информация связана — вся она относится к приложению.

Вся информация в приложении к нему относится. Это не делает ее связанной.

Чем, по-вашему, "$obj->property" остроконечников лучше чем "$obj[«property»] тупоконечников?

Семантикой. Первая запись подразумевает фиксированный набор хорошо известных свойств, вторая — изменяемый словарь.

(ц), (д) — тут прошу поподробнее. Чувствую ценность в вашем комментарии, но нужно больше деталей.

Тут придется пересказать всю историю реализаций IoC. Давайте я вас снова отправлю к хорошей книжке:
Dependency Injection in .NET. Это как раз тот случай, когда все описано очень конкретно и по делу.
Первая запись подразумевает фиксированный набор хорошо известных свойств, вторая — изменяемый словарь.


В .Net возможно, но не в PHP.

<?php
class TheClass
{
    public $ownProperty;
    public function getProp(){
        echo "Не существующее свойство: " . $this->property . "<br>";
    }
}

$obj = new TheClass();
$obj->property = "Существует.";
$obj->getProp(); // Не существующее свойство: Существует.
Я говорю про семантику записи, а не про конкретные возможности языка. Вы Макконнела читали?
Советую ознакомиться с презентацией Fabien Potencier (создателя вышеупомянутого Pimple, мэйнтейнера Symfony 2 и CEO Sensio Labs). Мне, в свое время, она очень помогла.
Надеюсь и мне поможет. Уже посмотрел 38 слайдов. Для демонстрации Dependancy Injection выбран хороший пример — класс «Пользователь» и хранение состояния в сессии.
Вы бы приличия ради уточнили, что именно вы понимаете под DI, а то есть ведь варианты.
Наверное, один из самых популярных шаблонов. Как правило, его все запоминают первым. А ещё при поиске работы про него очень любят спрашивать на собеседованиях. Еще надо знать, что многие считают этот шаблон антипаттерном. Я с этим мнением соглашусь в некоторой степени — части пытаются сделать синглтоном те объекты, которые никогда должны ими быть. К примеру, объект доступа к базе.
И это рано или поздно выливается в проблемы.
Основное применение реестра – в качестве безопасной замены глобальным переменным.

А можно подробнее про этот момент? Чем он безопаснее?

Глобальные переменные доступны для чтения/записи из любого места кода. Реестр — тоже. С помощью реестра можно просто организовать всё более централизованно. Но при чём тут «безопаснее»?
Ты наверное не помнишь, почему в своё время все отказались от использования глобальных переменных?? Предлагаю воспользоваться любимым поисковиком… ;)
Я знаю две проблемы с глобальными переменными:
1) конфликт имен
2) условно неопределенное поведение при импортировании ключей суперглобальных массивов в глобальную таблицу имен.

Первую проблему решают префиксы и пространства имен.
Вторая проблема решена отказом от директивы register_globals в PHP 5.4.

Отказываться от глобальных переменных я бы пока не стал.
Суть Registry в централизации доступа.

Основное применение реестра – в качестве безопасной замены глобальным переменным

Где Вы вообще такой бред находите?
И за такой ответ спасибо. Хотя, IMHO, посылать на х… яндекс или в ж… википедию на каждый вопрос в комментариях — много труда не нужно.
Обратите внимание, что я с самого начала спрашивал про то, «почему Registry безопаснее глобальных переменных», а не про «почему глобальные переменные плохо».

Именно интересовал вопрос про безопасность шаблона Registry, а не про то, почему лучше не использовать глобальные переменные.
Посылать к поисковикам плохо еще и потому (и это мое личное мнение), что в нашу дискуссию, обмен мнениями, привлекается мнение каких-то посторонних личностей. И ладно, если это признанные авторитеты, но зачастую это не так.
Как минимум, в Registry::set() можно вставить debug_print_backtrace() и понять, откуда пришло это значение.

В случае глобальных переменных отследить подобные вещи будет проблематично:

$_GET[rand(1,100)]  = rand(1,100);

Вы, похоже, говорите тут о суперглобальных переменных.
Вот отличии от суперглобальной $_GET, имеющей тип массива, обычная глобальная переменная может быть экземпляром какого-то (любого) класса со своим сеттером.
Кстати, интересная идея. Можно в геттере с помощью $stack = debug_backtrace() получить стек вызовов и взять значение $stack[1] (потому что в $stack[0] будет Registry), а потом через class_parents() получить всех предков. И, например, если в предках есть Controller, запретить напрямую использовать экземпляр класса DB (ссылку на который удобно хранить в реестре), чтобы авторы дополнительных модулей в контроллерах не писали SQL-запросы.

Это, конечно, на правах шутки, но в каждой шутке есть доля шутки.

Реестр действительно может дать больше контроля, оставляя при этом плюсы «глобальности».
В общем случае ничем, но есть возможность переопределения логики присваивания и возврата значений, чего нет у переменных. Например, в реестре мы легко можем:
— сделать присваивание одноразовым
— реализовать сложные проверки присваиваний (валидация типов и значений, например, в том числе для отдельных ключей)
— реализовать возвращение значений по умолчанию для неинициализированных элементов, в том числе для отдельных ключей, в том числе с конструированием объектов (непосредственно или через фабрики).
— сделать несколько инстансов реестра (если реализовать его как обычный объект, а не статический класс или синглтон) с разными значениями для одних ключей.
Признаю, в данном примере мало смысла. Здесь использование этого шаблона не оправдано. Я просто хотел показать его смысл.


А-аа--аа-аа! (крик души).

Я, кстати, целевая аудитория статьи. Кучу всего уже читал про паттерны, но до сих пор с трудом понимаю приводимые в статьях примеры и как они связаны с, например, вебсайтами (много процентов из которых на PHP).

Взять хотя реестр и пул объектов, вроде бы понятные сущности.
Я использую их для хранения состояния приложения.

Чтобы отстраниться от стереотипов, назовем его $STATE.

Подскажите, Благородные Доны, правильно ли я вижу паттерны в нижеследующем примитивном, но более приближенном к земле, как мне кажется, примере:

1) $STATE = array() — «реестр», он же «пул объектов» (db, page), он же «синглтон» (ибо глобальная переменная).
2) get_page_by_uri_from_somewhat_storage() — «фабрика» (или абстрактная?). Или это вообще «Строитель»?

<?php
require_once "classes/DB_Fabric.php";
require_once "classes/Renderer_Fabric.php";

$STATE = array();

$STATE["config"] = include "path/to/config.php";
$STATE["uri"]    = $_SERVER["REQUEST_URI"];
$STATE["db"]     = get_db_object();
$STATE["page"]   = get_page_by_uri_from_somewhat_storage();
$STATE["output"] = render_page();

echo $STATE["output"];
exit();

function get_db_object(){  // Возвращает объект "База данных" для текущего uri согласно конфигурации.
    global $STATE;
    
    return new DB_Fabric($STATE["config"]["db"], $STATE["uri"] );
}
function get_page_by_uri_from_somewhat_storage(){  // возвращает объект "Текущая страница" 
    global $STATE;

    if ( is_page_on_filesystem() ){
        return load_page_from_filesystem();
    } elseif( is_page_in_db() ) {
        return get_page_from_db();
    } else {
        return get_404_page();
    };
};
function is_page_on_filesystem(){
    global $STATE;
    
    $page_filename = $S["state"]["config"]["path_to_pages"] . $STATE["uri"];
    
    return is_readable($page_filename);
};
function load_page_from_filesystem(){
    global $STATE;
    
    return file_get_contents( $S["state"]["config"]["path_to_pages"] . $STATE["uri"] );
};
function is_page_in_db(){
    global $STATE;
    
    if ( $STATE["db"]->find("page", "by_uri", $STATE["uri"]) ) return true;
    else return false; 
};
function get_page_from_db(){
    global $STATE;
    
    return $STATE["db"]->find("page", "by_uri", $STATE["uri"]);
}
function render_page(){  //Возвращает представление страницы для User-Agent, используя подходящий renderer для текущего uri согласно конфигурации
    global $STATE;
    
    $renderer = new Renderer_Fabric( $STATE["config"], $STATE["uri"] );
    return $render->render( $STATE["page"]->data );
}


Покритикуйте мой пример.

Как его можно доработать, чтобы продемонстрировать другие порождающие шаблоны? Или другие тут не нужны?

Как его можно доработать, чтобы продемонстрировать другие порождающие шаблоны?

Это неправильный подход. Правильный подход звучит так: у меня есть следующая задача [...], какой паттерн подходит для ее решения?
Мы изучаем паттерны, поэтому задача обратная — понять, какие прикладные задачи с помощью какого паттерна решаются и как.
понять, какие прикладные задачи с помощью какого паттерна решаются и как.

Паттерны не решают прикладные задачи, паттерны структурируют код, который решает прикладные задачи.
Вообще есть такие задачи:
— ввод данных от пользователя
— вычисления (реализация бизнес-логики)
— хранения входных данных
— хранение промежуточных и окончательных результатов вычислений
— генерация HTML- (XML-, JSON-, ...) представления окончательных результатов вычислений
— вывод данных пользователю.

Какие паттерны подходит для их решения? Если несколько, то каким отдавать предпочтение и в каких случаях?

Ссылки можно не давать, интересует ваше (или тех, кто найдет смелость ответить на коммент) мнение и опыт.
На SO такие вопросы закрываются как too broad. Что значит «ввод данных от пользователя»? Консоль? Веб-приложение? GUI?

Для каждого из ваших пунктов есть список из паттернов, которые применяются в разработке. Вы GoF читали? А Фаулера? Там, в общем-то, все расписано, какой смысл цитировать тут книгу целиком?
Я предполагаю, что мы в контексте топика, т.е. задачи не слишком широкие, речь все еще о PHP. Давайте сузим до веб-приложений.

Этих великих деятелей, упомянутых вами, не читал. Не мой уровень, не дорос.
Но я пробовал читать Мэта Зандстру «PHP. Объекты, шаблоны и методики программирования» (не смог оценить шедевра) и сейчас начал читать Sanders W. — Learning PHP Design Patterns. Успел узнать о порождающих шаблонах фабрика и прототип. Но примеры там тоже не очень ясные.
Это далеко от моих реальных задач. Когда я читаю подобное, мне сложно представить, где я могу это применить в своих проектам. От того и не воспринимается информация…

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

Потому и пытаю всех вопросами.
В моей практике есть ровно два способа обучения людей, которые не могут прочитать книжку и увидеть применимости приведенного кода. Первый — это работа в паре с более опытным программистом, который будет разбирать конкретный код в ходе его написания и показывать, что именно должно быть применено (и в обратную сторону, анализ кода этого программиста с конкретными примерами). И второй — это прочитать все эти книжки лет через пять-десять успешной работы программистом, хлопнуть себя по лбу, и сказать «ах, так вот как это называется, оказывается».
На самом деле человек прав. Я знаю огромное количество программистов, которые изучают шаблоны проектирования, но совершенно не понимают когда и какой использовать. Да и тема эта в литературе не раскрыта.
Даже ссылки, которые вы даете человеку не дадут никакого понимания, что и где использовать. То что в каждом шаблоне описано где он может быть использован — абсолютно ничего не дает, так как слишком большое количество пересекающихся шаблонов по решению задач.

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


Что комментарии, в общем-то, и подтверждают.
Я пока иду по второму пути.
Конкретика.

$STATE = array() — «реестр», он же «пул объектов» (db, page), он же «синглтон» (ибо глобальная переменная).

Ни одно из них. Это просто глобальный словарь (весьма пакостный антипаттерн со всех сторон).

get_page_by_uri_from_somewhat_storage() — «фабрика» (или абстрактная?). Или это вообще «Строитель»?

Ни то, ни другое, ни третье. Метод, читающий что-то откуда-то, в норме не относят к порождающим паттернам.
Хорошо, «глобальный словарь» и «реестр» это разные слова. Но означают они что-то близкое, если не одно и то же. И туда и сюда можно положить данные и извлечь, и можно сделать это из любого места программы.

Метод, читающий что-то откуда-то, в норме не относят к порождающим паттернам


Что тут имеется в виду? Данные в программу вводятся извне, в любом случае, что-то откуда-то прочитается: от пользователя, из конфига, из хранилища. Да и и get_page_by_uri_from_somewhat_storage() сам не читает ничего, а вызывает другие функции.
Но означают они что-то близкое, если не одно и то же.

Не одно и то же. Вот такие мелочи и отличают паттерн (то есть, отработанное временем решение) от вроде-бы-того-же-самого, но на самом деле — опасной ошибки.

Конкретно в вашем случае — это просто глобальное состояние, совершенно не понятно, зачем примененное, и от этого очень опасное.

Что тут имеется в виду?

Имеется в виду, что тот метод, о котором вы говорите — это не фабрика (ни в каком ее виде).
от такие мелочи и отличают паттерн

Хорошо бы вы указали на эти мелочи, пока они остаются загадкой.

совершенно не понятно, зачем примененное, и от этого очень опасное

Этим грешат и паттерны, когда они не понятны.

В моем случае я тоже использую паттерн, только он вам не известен.
Использование $STATE направлено на снижение связности модулей программы и инкапсуляции их поведения и свойств.
В примере это можно заметить (убрав шоры с глаз) по отсутствию параметров у функций.
Когда изменится имплементация той или иной функции, ее сигнатура не изменится.
Каждая функция берет нужные ей входные данные в реестре и может помещать туда промежуточные данные или результат.

Применяется паттерн только в главное программе или в контроллере (при использовании MVC).

Кроме того, такой подход позволяет описывать главную программу (контроллер) декларативно. Из примера этого не видно, впрочем

Хорошо бы вы указали на эти мелочи, пока они остаются загадкой.

Реестр содержит семантически связанные и (в норме) однотипные объекты. Может быть реестр сервисов, может быть реестр (конкретных) данных, но не может быть реестра всего — это уже god object.

Использование $STATE направлено на снижение связности модулей программы

Угу, вместо того, чтобы связать два модуля через хорошо известный обоим контракт, нужно оба их связать с вашим $STATE, причем без возможности определить контракт. Как вы (инструментально) отслеживаете корректность обращения к данным в $STATE?

Глобальная область видимости — это плохо. Это плохо именно потому, что у вас нарушается принцип единой ответственности.
Реестр содержит семантически связанные и (в норме) однотипные объекты.

Справедливо.

связать два модуля через хорошо известный обоим контракт,

В общем модулей сильно больше двух. И каждый из них связан только со $STATE. $STATE не обязан быть массивом. В более сложных случаях это будет объект с кастомными сеттерами/геттерами.

Глобальная область видимости — это плохо. Это плохо именно потому, что у вас нарушается принцип единой ответственности.

Нарушать этот принцип вовсе не обязательно. Глобальная область это просто верхний уровень. Погружение внутрь хорошо для библиотек и т.п., но для основной программы это, по моему, лишнее.
В общем модулей сильно больше двух. И каждый из них связан только со $STATE.

Представьте себе, что у вас в системе полторы тысячи модулей, и в каждом из них где-нибудь по три-пять сегментов данных, которыми нужно обмениваться. Пять-восемь тысяч свойств $STATE, you kidding?

Ну и вы не ответили про средства инструментального контроля.

Погружение внутрь хорошо для библиотек и т.п., но для основной программы это, по моему, лишнее.

Отнюдь. Это все хорошо только пока у вас мало кода, и он простой. С возрастанием сложности необходимость инкапсуляции растет.

По факту, многие современные крупные системы имеют «лаунчер» на полстранички, и это единственное место, где появляются по-настоящему глобальные значения, а дальше они передаются в каждый модуль как локальные.
Реестр содержит семантически связанные и (в норме) однотипные объекты.

Это откуда? Всегда воспринимал реестр как некое рантайм хранилище чего угодно. Да, можно делать специализированные, типизированные, но это уже ближе к пулу, нет?
Это из чтения Фаулера и моего понимания SRP. Иначе неизбежен год-обжект.
У реестра одна ответственность — хранить значения (в том числе объекты, ресурсы и массивы в контексте PHP) в рантайме для всего приложения. Какое отношение имеет тип этих значений или их семантическая близость к ответственности?
У реестра одна ответственность — хранить значения (в том числе объекты, ресурсы и массивы в контексте PHP) в рантайме для всего приложения.

Слово «всего» — лишнее. Не для всего приложения, а для заинтересованных сторон. Соответственно, дальше у вас начинается типичный граф зависимостей. Чем больше зависимостей (для конкретного реестра), тем сложнее им управлять и поддерживать. Соответственно, если вы разделяете реестр сервисов с реестрами данных, а в реестрах данных разделяете реестр пользователей и реестр документов, то каждый из реестров становится существенно проще (не говоря уже о том, что пропадает необходимость придумывать способы обеспечения уникальности ключей).
Ну, если есть нужда хранения разнотипных наборов однотипных данных, то естественно лучше каждый набор однотипных данных выделять в отдельную сущность. Но вот если однотипных значений одно-два (типа коннектов к СУБД), то вполне вероятно, что создание отдельного реестра на каждый тип будет выглядеть оверинженерингом. Хотя, конечно, общего рецепта нет.
Но вот если однотипных значений одно-два (типа коннектов к СУБД), то вполне вероятно, что создание отдельного реестра на каждый тип будет выглядеть оверинженерингом.

Плохой пример. Зачем хранить коннекты к БД в общедоступном реестре?

(впрочем, реестр — вообще очень посредственный паттерн, сам Фаулер об этом пишет)
Я просто оставлю это здесь:

«Приемы объектно-ориентированного проектирования. Паттерны проектирования»
Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес

ISBN 978-5-469-01136-1, 5-272-00355-1, 0-201-63361-2,5-469-01136-4; 2007 г.
Просто попробуй разобраться в этой книге и применить эти паттерны к языку отличному от smalltalk
Разобрался.
Вообще говоря это книжка скорее теоретическая, нежели практическая и не важно на каком из языков примеры.

Если человек не способен понять содержание этой книги, наверное ему пока что рано в паттерны.
По PHP есть похожая книжка, которая также может навести порядок в мыслях:
«PHP. Объекты, шаблоны и методики программирования»
Мэт Зандстра
ISBN 978-5-8459-1689-1, 978-1-43-022925-4; 2011 г.

Лично мне очень понравилась, рекомендую. Из особенностей: похоже, она для версии PHP 5.3.

Упомянута, в частности, тут.
Итак, мы рассмотрели 9 шаблонов проектирования. Это довольно длинная статья. Поэтому хотелось бы узнать ваше мнение. Есть ли смысл в проделанной работе и стоит ли мне завершить цикл, рассказав о структурных шаблонах и шаблонах поведения?

Спасибо за пост! Смысл определённо есть. Ждём продолжения.
Очень наглядный пост, пожалуйста, продолжайте.
Only those users with full accounts are able to leave comments. Log in, please.