Интересные разделы:
Php
Шаблон Dependency InjectionОбнавлено: 04.02.2020

В этой статье подробно описан механизм работы патерна Dependency Injection

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

Задача

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

class AppointmentMaker
{
    public function makeAppointment()
    {
        $encoder = new BloggsApptEncoder();
        return $encoder->encode();
    }
}

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

$factory = new TerrainFactory(
    new EarthSea(),
    new EarthPlains,
    new EarthForest
);

Вызов класса TerrainFactory – это шаг в правильном направлении. Для получения экземпляра требуются универсальные типы Sea, Plains и Forest. Этот класс позволяет клиентскому коду выбирать реализацию для предоставления. Но как ты это делаешь?

Решение

Большая часть кода, обсуждаемого здесь, требует доступа к фабрикам. И, как показано выше, это такая модель, называемая моделью сервисного локатора, согласно которой метод делегирует провайдеру, которому он полностью доверяет, ответственность за поиск и поддержание требуемого типа данных. Ситуация совершенно иная в примере использования модели Prototype, где просто ожидается, что при вызове кода для получения экземпляра будут предоставлены соответствующие реализации. И в этом нет ничего необычного, потому что достаточно предоставить типы данных, требуемые в сигнатуре конструктора, а не создавать их в самом методе. В противном случае вы можете указать методы установки, чтобы клиенты могли отправлять объекты перед вызовом метода, в котором они используются. Мы внесем следующие изменения в класс AppointmentMaker:

class AppointmentMaker2
{ 
    private $encoder;
    public function __construct(ApptEncoder $encoder)
    {
        $this->encoder = $encoder;
    }
    
    public  function makeAppointment()
    {
        return $this->encoder->encode();
    }
}

Таким образом, мы достигаем желаемой гибкости благодаря тому, что класс AppointmentMaker2 возвращает элемент управления – объект типа BloggsApptEncoder 8 больше не создается. Но как работает логика создания объектов и где новые вдохновляющие операторы? Для выполнения этих задач вам понадобится коллекторный компонент. Как правило, файл конфигурации используется для этой цели, где определенные реализации определены для получения экземпляров. И хотя здесь можно использовать вспомогательные инструменты, эта книга посвящена тому, как самостоятельно выбраться из таких ситуаций. Поэтому сначала мы попытаемся создать очень простую реализацию, начиная с несложного файла конфигурации в формате XML, который описывает отношения между классами в разрабатываемой системе и конкретными типами данных, которые должны быть переданы вашим дизайнерам.

<object>
    <class name="TerrainFactory">
        <arg num="0" inst="EarthSea" />
        <arg num="1" inst="MarsPlains" />
        <arg num="2" inst="EarthForest" />
    </class>
    
    <class>
        <arg num="0" inst="BloggsApptEncoder"></arg>
    </class>
</object>

Здесь описаны два класса, TerrainFactory и AppointmentMaker2, упомянутые в этой главе. Вы должны получить экземпляр класса TerrainFactory, используя объекты типа EarthSea, MarsPlains и EarthForest, и чтобы объект типа BloggsApptEn-coder был передан в класс AppointmentMaker2. Ниже приведен очень простой пример класса коллекции, который считывает данные конфигурации и извлекает экземпляры объектов по запросу.

class ObjectAssemЫer
{
    private $components = [];

    public function __construct(string $conf)
    {
        $this->configure($conf);
    }

    private function configure(string $conf)
    {
        $data = simplexml_load_file($conf);
        foreach ($data->class as $class) {
            $args = [];
            $name = (string)$class['name'];
            foreach ($class->arg as $arg) {
                $argclass = (string)$arg['inst'];
                $args[(int)$arg['num']] = $argclass;
            }
            ksort($args);
            $this->components[$name] = function () use ($name, $args) {
                $expandedargs = [];
                foreach ($args as $arg) {
                    $expandedargs[] = new $arg();
                }
                $rclass = new \ReflectionClass($name);
                return $rclass->newinstanceArgs($expandedargs);
            };
        }
    }

    public function getComponent(string $class)
    {
        if (!isset($this->components[$class])) {
            throw new \Ехсерtiоn("Неизвестный компонент '$class'");
        }
        $ret = $this->components[$class] ();
        return $ret;
    }
}

Это очень просто, хотя на первый взгляд немного сложно понять реализацию, поэтому давайте кратко рассмотрим ее. Основное действие происходит в методе configure (), которому передается путь к файлу конфигурации, полученному от производителя. Он анализирует расширение sirnplexml для анализа файла конфигурации .xml. Если в реальном проекте требуется более глубокая обработка ошибок, в этом примере мы полностью доверяем содержимому проанализированного файла конфигурации XML. сначала полностью извлекается из каждого элемента разметки
конкретное имя класса, которое хранится в переменной $ name. Затем аргументы, соответствующие именам требуемых отдельных классов, извлекаются из подчиненных элементов разметки . Они хранятся в массиве $ args и сортируются по значению аргумента разметки xml num. Полученные данные собираются в анонимной функции, хранящейся в свойстве $ components. В этой функции получается экземпляр запрошенного класса и всех требуемых им объектов, и поэтому он вызывается только тогда, когда вызывается метод getComponent () с правильным именем класса. По этой причине довольно маленький фрагмент собранной информации может храниться в классе ObjectAssember. Обратите внимание на применение закрытия. В частности, анонимная функция обращается к переменным $ name и $ args, объявленным в области видимости при ее создании, с помощью ключевого слова use. Это, конечно, экспериментальный код. В дополнение к улучшенной обработке ошибок для ее надежной реализации необходимо будет учитывать, что сами объекты, включенные в компонент, могут требовать аргументов. Или вам может понадобиться решить проблемы с кэшированием. Например, вы должны получать экземпляр объекта каждый раз или только один раз?

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

$assemЬler = new ObjectAssemЬler("objects.xml"); 
$apptmaker = $assemЬler->getComponent("AppointmentMaker2"); 
$out = $apptmaker->makeAppointment(); 
print $out; 

С классом ObjectAssemЬler одной инструкции достаточно для получения экземпляра объекта. Класс AppointmentMaker2 теперь свободен от старой жестко заданной зависимости для экземпляра класса ApptEncoder. Кроме того, разработчик может использовать файл конфигурации, отслеживать классы, используемые во время теста, … и даже тестировать класс AppointmentMaker2 отдельно от остальной системы в более широком контексте.

Заключение

Мы рассмотрели две возможности создания объектов. С одной стороны, класс AppConfig послужил примером использования модели Service Locator, предоставляя возможность обнаруживать компоненты или службы от имени вашего клиента. Конечно, внедрение зависимости помогает писать более элегантный код. Итак, в классе AppointmentMaker2 ничего не известно о стратегиях создания объектов. Он просто выполняет свои обязанности, что, конечно, идеально подходит для любого класса. Мы стремимся разрабатывать классы, которые могут максимально сосредоточиться на своих обязанностях, отдельно от остальной системы. Но такая чистота не достигается бесплатно, потому что для этого необходим отдельный компонент коллектора для выполнения всех необходимых действий. Это можно считать «черным ящиком», доверяющим ему создавать объекты, как будто с помощью магии от нашего имени. И если эта магия работает правильно, то мы достаточно счастливы. Но в то же время «будет нелегко отладить неожиданное поведение такого черного ящика». С другой стороны, модель Service Locator является более простой, хотя она требует включения компонентов в остальную часть системы. Однако модель Service Locator не усложняет тестирование и не делает систему гибкой при правильном использовании. Идентификатор службы Service Locator может быть настроен для обслуживания произвольных компонентов в целях тестирования или в соответствии с указаниями. Но закодированный вызов идентификатора службы делает компонент зависимым от него. И поскольку этот вызов выполняется в теле метода, связь между клиентским кодом и целевым компонентом, предоставляемым моделью локатора службы, несколько скрыта. Ведь такое соотношение указано в подписи метода построения. Какой подход лучше выбрать? В какой-то степени это вопрос личных предпочтений. Лично я предпочитаю начинать с самого простого решения, постепенно усложняя его по мере необходимости. По этой причине я обычно выбираю модель Service Locator, создаю класс с использованием модели Registry в несколько строк кода и, следовательно, повышаю его гибкость в соответствии с конкретными требованиями. Компоненты, которые я разрабатываю, больше осведомлены друг о друге, чем хотелось бы, но, поскольку я редко переношу классы из одной системы в другую, я не особенно страдаю от эффекта внедрения. Например, после перемещения системного класса в отдельную библиотеку я не обнаружил трудностей в устранении зависимости, полученной из модели Service Locator. Модель Dependency Injection обеспечивает чистоту, но требует некоторого включения и заставляет вас полагаться на коллектор. Если вы используете фреймворк, в котором подобная функциональность уже предусмотрена, вам вряд ли стоит отказываться от его услуг. Например, Symfony DI предоставляет гибридное решение для поиска шаблонов услуг.

Шаблон Service LocatorОбнавлено: 03.02.2020

В этой статье подробно описан шаблон Service Locator

Как и было обещано, в этой статье следует поговорить о логике создания объекта, а не о конкретных примерах ООП. Но некоторые из моделей, обсуждаемых здесь, скрывают хитроумные решения о создании объектов, если не сами объекты. Синглтонский мотив не может быть привлечен к ответственности. Логика создания интегрированных объектов совершенно однозначна. В модели Factory создание семейств продуктов группируется по разным конкретным классам производителей. Но как вы выбираете конкретного производителя? Аналогичная трудность возникает при использовании модели Prototype. Эти две модели участвуют в создании объектов, но они задерживают решение о том, какой конкретный объект (или группу объектов) создавать. Решение о выборе конкретного производителя обычно принимается на основании заданного значения параметра конфигурации. Этот параметр может находиться в базе данных, в файле конфигурации или в файле на сервере (например, в файле конфигурации на уровне каталогов на сервере Apache; обычно он называется .htaccess) или даже может быть закодирован как переменная или свойство в PHP. А поскольку конфигурация приложения в PHP должна изменяться для каждого запроса, инициализация сценария должна быть максимально простой. Поэтому я обычно прибегаю к встроенной кодировке значений флагов конфигурации в коде PHP. Вы можете сделать это вручную или написать скрипт для автоматической генерации файла класса. Вот пример класса конфигурации, который включает параметр для указания типа календарного протокола.

class Settings
{
	static $COMMSTYPE = 'Bloggs';
}

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

class AppConfig
{
    private static $instance;
    private $commsManager;

    private function __construct()
    {
        $this->init();
    }

    private function init()
    {
        switch (Settings::$COMMSTYPE) {
            case 'Mega':
                $this->commsManager = new MegaCommsManager();
                break;
            default:
                $this->commsManager = new BloggsCommsManager();
        }
    }

    public static function  getInstance() : AppConfig
    {
        if(empty(self::$instance)){
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getCommsManager() : CommsManager
    {
        return $this->commsManager();
    }
}

Класс AppConfig является стандартным одноэлементным классом, поэтому мы можем легко получить ссылку на экземпляр AppConfig в любом месте нашей программы, и он всегда будет ссылкой на один и тот же экземпляр. Метод init () вызывается конструктором класса и поэтому выполняется только один раз во время выполнения программы. Этот метод проверяет значение свойства Settings::$COMMSTURE и создает экземпляр указанного объекта CommsManager, как показано ниже. Теперь в скрипте вы можете получить объект типа CommsManager и работать с ним, даже не зная его конкретных реализаций или конкретных классов, которые он создает.

$commsMgr = AppConfig::getInstance()->getCommsManager();
print $commsMgr->getApptEncoder()->encode();

Класс AppConfig автоматически организует поиск и создание компонентов и, следовательно, действует как типичный пример применения модели Service Locator. Это элегантная модель, хотя она создает зависимость в менее легкой форме, чем прямая инициализация. Во всех классах, которые используют такой монолитный сервис, созданный в соответствии с этой моделью, необходимо вызывать его явно, что связывает их с остальной частью системы в более широком контексте. Вот почему некоторые предпочитают выбирать другой подход.

Шаблон PrototypeОбнавлено: 02.02.2020

В этой статье подробно описан Шаблон Prototype. Прочитав данную статью вы сможете эфектвно использовать данный патернн в своих проектах

Если используется шаблон Factory, возникновение параллельных иерархий наследования может привести к осложнениям. Такое тесное соединение делает некоторых программистов неудобными. Каждый раз, когда вводится новое семейство продуктов, вам нужно создать конкретного производителя. В быстро растущей системе со многими продуктами поддержание этого типа связи может быстро стать очень утомительной проблемой. Чтобы устранить этот тип зависимости, вы можете использовать ключевое слово PHP clone, в частности, для дублирования некоторых существующих продуктов. И тогда определенные классы продуктов становятся основой для создания ваших собственных объектов. По сути, это означает, что используется паттерн Prototype, в результате чего наследование может быть заменено композицией. Этот подход, в свою очередь, способствует гибкости в выполнении программы и уменьшает количество создаваемых классов.

Задача

Представьте себе интернет-игру цивилизационного типа, в которой элементы работают на клеточном поле. Каждая клетка может представлять море, равнину или лес. Тип местности может ограничивать движение и способность элементов занимать ячейку. Предположим, у нас есть объект TerrainFactory (Фабрика области), который позволяет нам создавать Море (море), Лес (лес) и Равнины (равнины). Мы решили дать пользователю возможность выбирать совершенно разные типы сред. Следовательно, объект Sea относится к абстрактному суперклассу, реализованному в классах MarsSea и EarthSea. Такие объекты, как Лес и Равнины, реализованы одинаково. В этом случае вы можете использовать шаблон A Abstract Factory. У нас есть различные иерархии продуктов (море, лес, равнины) с крепкими семейными отношениями, включая наследование (земля, Марс). На изображение снизу показана диаграмма классов, иллюстрирующая, как шаблоны и фабрика Abstract Factory могут использоваться для работы с этими продуктами. Как видите, мы используем наследование для группировки семейств типов местности для продуктов, которые будут производиться на заводе. Это уместно, но требует большой иерархии наследования и недостаточно гибкости.

Реализация

Используя модели A Abstract Factory и Factory Method, мы должны решить в конкретное время, с каким конкретным производителем нам следует работать. Вероятно, это можно сделать, проанализировав значения некоторых флагов. И поскольку мы должны сделать это так или иначе, почему бы не создать фабричный класс для хранения определенных продуктов и их распространения во время инициализации? Таким образом, мы можем избавиться от разных классов и, как мы скоро увидим, использовать их другие преимущества. Ниже приведен пример простого кода, который использует шаблон Prototype в качестве фабрики.

<?php

//// SEA ////
class Sea
{
}
class EarthSea extends Sea
{
}
class MarsSea extends Sea
{
}

//// PLAINS////
class Plains
{
}
class EarthPlains extends Plains
{
}
class MarsPlains extends Plains
{
}

//// FOREST ////
class Forest
{
}
class EarthForest extends Forest
{
}
class MarsForest extends Forest
{
}

// TERRAIN FACTORY
class TerrainFactory
{
    private $sea;
    private $forest;
    private $plain;

    public function  __construct(Sea $sea, Plains $plains, Forest $forest)
    {
        $this->sea = $sea;
        $this->plain = $plains;
        $this->forest = $forest;
    }
    public  function getSea(): Sea
    {
        return clone $this->sea;
    }
    public  function getPlains(): Plains
    {
        return clone $this->plain;
    }
    public  function getForest(): Forest
    {
        return clone $this->forest;
    }
}

$factory = new TerrainFactory(
    new EarthSea(),
    new EarthPlains(),
    new EarthForest()
);
print_r($factory->getSea());
print_r($factory->getPlains());
print_r($factory->getForest());

Как вы можете видеть, экземпляры объектов различных продуктов загружаются в экземпляр конкретной фабрики, такой как TerrainFactory. Когда метод getSea () вызывается в клиентском коде, он возвращает клон объекта Sea, который кэшируется во время инициализации. В результате нам удалось не только сократить несколько классов, но и добиться некоторой гибкости. Вы хотите, чтобы игра происходила на новой планете с морями и лесами, как на Земле, и с равнинами, как на Марсе? Для этого вам не нужно создавать новый класс производителя, а нужно только изменить набор классов, представленных в TerrainFactory, как показано ниже.

$factory = new TerrainFactory(
    new EarthSea(),
    new EarthPlains(),
    new EarthForest()
);

Таким образом, модель Prototype позволяет вам воспользоваться гибкостью, которую предлагает композиция. Но у нас есть нечто большее. В конце концов, мы сохраняем и клонируем объекты во время выполнения программы, что означает, что мы воспроизводим состояние объектов при создании новых продуктов.

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

Шаблон FactoryОбнавлено: 01.02.2020

В этой маленькой статье подробно описан шаблон Factory Method

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

Решение

В шаблоне Factory методы производителя отделены от продуктов, которые они должны создать. Производитель – это фабричный класс, который определяет метод формирования объекта из одного продукта. Если стандартная реализация этого метода не предусмотрена, извлечение экземпляра объекта поручается дочерним классам производителя. Как правило, экземпляр дочернего класса продукта получается в каждом подклассе производителя. Переопределите класс MainManager как абстрактный. Таким образом, мы храним гибкий суперкласс и организуем весь код, назначенный конкретному протоколу, в отдельные подклассы

<?php

abstract class MainEncoder
{
    abstract public function encode(): string;
}

class M2bEncoder extends MainEncoder
{
    public function encode(): string
    {
        return "Данные закодированны в M2b \n";
    }
}

class CtbEncoder extends MainEncoder
{
    public function encode(): string
    {
        return "Данные закодированны в Ctb \n";
    }
}

abstract class MainManager {
    abstract public function getHeaderText(): string;
    abstract public function getApptEncoder(): MainEncoder;
    abstract public function getFooterText(): string;
}

class ManagerOne extends MainManager
{
    public function getHeaderText(): string
    {
        return "M2b Шапка \n";
    }

    public function getApptEncoder(): MainEncoder
    {
        return new M2bEncoder();
    }

    public function getFooterText(): string
    {
        return "M2b Футер \n";
    }
}

class ManagerTwo extends MainManager
{
    public function getHeaderText(): string
    {
        return "Ctb Шапка \n";
    }

    public function getApptEncoder(): MainEncoder
    {
        return new CtbEncoder();
    }

    public function getFooterText(): string
    {
        return "Ctb Футер \n";
    }
}

$manager = new ManagerOne();
print $manager->getHeaderText();
print $manager->getApptEncoder()->encode();
print $manager->getFooterText();

Заключение

Обратите внимание, что классы производителей отражают иерархию продуктов. Это обычный результат, полученный при применении модели фабричного метода. Некоторые программисты рассматривают эту модель как особый тип дублирования кода и поэтому часто не любят ее. Другим недостатком модели фабричного метода является то, что она часто способствует ненужной подклассификации. Поэтому, если применение модели Factory не должно образовывать подклассы производителя и нет других причин для его использования, рекомендуется тщательно обдумать это прежде. Если мы немного расширим этот пример, включив элементы деятельности и контакты, мы столкнемся с новой проблемой. Нам понадобится структура, которая должна одновременно управлять рядом связанных реализаций. Следовательно, модель фабричного метода часто используется с абстрактной фабричной моделью.

Php

В этом разделе Web разработчики собрали материалы на тематику Php. Если у вас есть желание изучить данный язык программирования, то начните отсюда. Сегодня существуют множества различных фреймворков, СMS таких как Wordpress, Symfony, Drupal и все они написанны на языке Php. Прежде чем начать учить какой либо фремворк или Cms, для начало изучите язык программирования Php. Php используют в Backend разработке. Данный инструмент встроен во множество различных хостингов. Php является самым эффективным инструментом для Web разработки из всех существующих языков программирования. Сообщество Php очень большое, создаются различные плагины, пишутся программы для взаимодействия с серверами. Php постоянно обнавляется и улучшается что дает прирост к производительности данного языка программирования, исправляются баги, добавляются различные возможности и т д.