Шаблони проектування звичною мовою. Частина третя. Поведінкові шаблони


Дізнайтесь більше про нові кар'єрні можливості в EchoUA. Цікаві проекти, ринкова оплата, гарний колектив. Надсилайте резюме та приєднуйтеся до нас.

Розповідає Камран Ахмед


Шаблони проектування – це керівництво по рішенню проблем, що повторюються. Це не класи, пакети або бібліотеки, які можна було б підключити до вашого застосування і сидіти в очікуванні дива. Вони швидше є методиками, як вирішувати певні проблеми в певних ситуаціях.

Вікіпедія описує їх таким чином:

Шаблон проектування, чи патерн, у розробці програмного забезпечення – повторювана архітектурна конструкція, що є вирішенням проблеми проектування, у рамках деякого часто виникаючого контексту.

Будьте обережні

  • шаблони проектування не є рішенням усіх ваших проблем;
  • не намагайтеся насильно використати їх, через це можуть статися погані речі. Шаблони – рішення проблем, а не рішення для пошуку проблем;
  • якщо їх правильно використати в потрібних місцях, то вони можуть стати порятунком, а інакше можуть привести до жахливого безладу.

Також зверніть увагу, що приклади нижче написані на PHP 7. Але це не повинно вас зупиняти, адже принципи залишаються такими ж.

Типи шаблонів

Шаблони бувають наступних трьох видів:

  1. Що породжують.
  2. Структурні.
  3. Поведінкові про них ми розповідаємо в цій статті.

Простими словами: Поведінкові шаблони пов’язані з розподілом обов’язків між об’єктами. Їх відмінність від структурних шаблонів полягає в тому, що вони не просто описують структуру, але також описують шаблони для передачі повідомлень / зв’язку між ними. Або, іншими словами, вони допомагають відповісти на питання “Як запустити поведінку в програмному компоненті”?

Вікіпедія свідчить:

Поведінкові шаблони – шаблони проектування, що визначають алгоритми і способи реалізації взаємодії різних об’єктів і класів.

Поведінкові шаблони:

Ланцюжок обов’язків (Chain of Responsibility)

Вікіпедія свідчить:

Ланцюжок обов’язків – поведінковий шаблон проектування призначений для організації в системі рівнів відповідальності.

Приклад з життя: наприклад, у вас є три платіжні методи (A, B і C), налаштовані на ваш банківський рахунок. На кожному лежить різна кількість грошей. На A є 100 доларів, на B є 300 доларів і на C – 1000 доларів. Перевага віддається в наступному порядку: A, B і C. Ви намагаєтеся замовити щось, що коштує 210 доларів. Використовуючи ланцюжок обов’язків, першим на можливість оплати буде перевірений метод А, і у разі успіху пройде оплата, і ланцюг розірветься. Якщо ні, то запит перейде до методу B для аналогічної перевірки. Тут A, B і C – це ланки ланцюга, а усе явище – ланцюжок обов’язків.

Простими словами: ланцюжок обов’язків допомагає будувати ланцюжки об’єктів. Запит входить з одного кінця і проходить через кожен об’єкт, поки не знайде відповідний обробник.

Звернемося до коду. Наведемо приклад з банківськими рахунками. Спочатку у нас базовий Account з логікою для з’єднання рахунків ланцюгом і деякі рахунки:

abstract class Account{ protected $successor; protected $balance; public function setNext (Account $account) { $this ->successor = $account; } public function pay (float $amountToPay) { if ($this ->canPay ($amountToPay)) { echo sprintf ('Оплата %s, використовуючи %s'. PHP_EOL, $amountToPay, get_called_class()); } elseif ($this ->successor) { echo sprintf (Не 'можна заплатити, використовуючи %s. Обробка .'. PHP_EOL, get_called_class()); $this ->successor ->pay ($amountToPay); } else { throw new Exception ('Ні на одному з аккаунтів немає необхідної кількості грошей'); } }
public function canPay ($amount): bool { return $this ->balance >= $amount; }}class Bank extends Account{ protected $balance; public function __construct (float $balance) { $this ->balance = $balance; }}class Paypal extends Account{ protected $balance; public function __construct (float $balance) { $this ->balance = $balance; }}class Bitcoin extends Account{ protected $balance; public function __construct (float $balance) { $this ->balance = $balance; }}

Тепер приготуємо ланцюг, використовуючи оголошені вище ланки (наприклад, Bank, Paypal, Bitcoin) :

// Підготуємо ланцюг// $bank ->$paypal ->$bitcoin//// Перший по пріоритету банк// Якщо не можна через банк, то Paypal// Якщо не можна через Paypal, то Bitcoin
$bank = new Bank (100); // Банк з балансом 100$paypal = new Paypal (200); // Paypal з балансом 200$bitcoin = new Bitcoin (300); // Bitcoin з балансом 300$bank->setNext ($paypal);$paypal ->setNext ($bitcoin);// Спробуємо сплатити через банк$bank ->pay (259);// Висновок// ==============// не Можна заплатити, використовуючи Банк. Обробка .// не Можна заплатити, використовуючи Paypal. Обробка .:// Оплата 259, використовуючи Bitcoin!

Приклади на Java і Python.

Команда (Command)

Вікіпедія свідчить:

Команда – поведінковий шаблон проектування, використовуваний при об’єктно-орієнтованому програмуванні, представляє дію. Об’єкт команди містить в собі сама дія і його параметри.

Приклад з життя: Типовий приклад: ви замовляєте їжу в ресторані. Ви (тобто Client) просите офіціанта (наприклад, Invoker) принести їжу (тобто Command), а офіціант просто переправляє запит шеф-кухареві (тобто Receiver), який знає, що і як готувати. Іншим прикладом може бути те, що ви (Client) включаєте (Command) телевізор (Receiver) за допомогою пульта дистанційного керування (Invoker).

Простими словами: Дозволяє вам инкапсулировати дії в об’єкти. Основна ідея, що стоїть за шаблоном, – це надання засобів, для розділення клієнта і одержувача.

Звернемося до коду. Спочатку у нас є одержувач Bulb, у якому є реалізація кожної дії, яка може бути виконана :

// Получательclass Bulb{ public function turnOn (){ echo "Лампочка спалахнула"; } public function turnOff (){ echo "Темрява"!; }}

Потім у нас є інтерфейс Command, яка кожна команда повинна реалізовувати, і потім у нас буде набір команд :

interface Command{ public function execute (); public function undo (); public function redo ();}// Командаclass TurnOn implements Command{ protected $bulb; public function __construct (Bulb $bulb) { $this ->bulb = $bulb; } public function execute (){ $this ->bulb ->turnOn (); } public function undo (){ $this ->bulb ->turnOff (); } public function redo (){ $this ->execute (); }}
class TurnOff implements Command{ protected $bulb; public function __construct (Bulb $bulb) { $this ->bulb = $bulb; } public function execute (){ $this ->bulb ->turnOff (); } public function undo (){ $this ->bulb ->turnOn (); } public function redo (){ $this ->execute (); }}

Потім у нас є Invoker, з яким клієнт взаємодіятиме для обробки будь-яких команд :

// Invokerclass RemoteControl{ public function submit (Command $command) { $command ->execute (); }}

Нарешті, ми можемо побачити, як використати нашого клієнта:

$bulb = new Bulb ();$turnOn = new TurnOn ($bulb);$turnOff = new TurnOff ($bulb);$remote = new RemoteControl ();
$remote ->submit ($turnOn); // Лампочка спалахнула!$remote ->submit ($turnOff); // Темрява!

Шаблон команда може бути використан для реалізації системи, грунтованої на транзакціях, де ви зберігаєте історію команд, як тільки їх виконуєте. Якщо остаточна команда успішно виконана, то все добре, інакше алгоритм просто перебирає історію і продовжує виконувати відміну для усіх виконаних команд.

Приклади на Java і Python.

Ітератор (Iterator)

Вікіпедія свідчить:

Ітератор – поведінковий шаблон проектування. Є об’єктом, що дозволяє отримати послідовний доступ до елементів об’єкту-агрегату без використання описів кожного з агрегованих об’єктів.

Приклад з життя: Старий радіонабір буде хорошим предметом ітератора, де користувач може почати шукати сигнал на якомусь каналі і потім використати кнопки перемикання на наступний і попередній канал для переходу між відповідними каналами. Або використуємо приклад телевізора, де ви можете натискати кнопки наступного або попереднього каналу для переходу через послідовні канали, або, іншими словами, вони надають інтерфейс для ітерировання між відповідними каналами, піснями або радіостанціями.

Простими словами: Представляє спосіб доступу до елементів об’єкту без показу базового представлення.

Звернемося до прикладів у коді. У PHP дуже просто реалізувати це, використовуючи SPL (Standard PHP Library). Наводячи наш приклад з радіостанціями, спочатку у нас є Radiostation:

class RadioStation{ protected $frequency; public function __construct (float $frequency) { $this ->frequency = $frequency; } public function getFrequency (): float { return $this ->frequency; }}

Потім у нас є ітератор:

use Countable;use Iterator;class StationList implements Countable, Iterator{ /** @var RadioStation[] $stations */ protected $stations =[]; /** @var int $counter */ protected $counter; public function addStation (RadioStation $station) { $this ->stations[] = $station; } public function removeStation (RadioStation $toRemove) { $toRemoveFrequency = $toRemove ->getFrequency ();
$this ->stations = array_filter ($this ->stations, function (RadioStation $station) use ($toRemoveFrequency) { return $station ->getFrequency ()!== $toRemoveFrequency; }); } public function count (): int { return count ($this ->stations); } public function current (): RadioStation { return $this ->stations[$this ->counter]; } public function key (){ return $this ->counter; } public function next (){ $this ->counter++; } public function rewind (){ $this ->counter = 0; } public function valid (): bool { return isset ($this ->stations[$this ->counter]); }}

Приклад використання :

$stationList = new StationList ();// Додавання станцій$stationList ->addStation (new RadioStation (89));
$stationList ->addStation (new RadioStation (101));$stationList ->addStation (new RadioStation (102));$stationList ->addStation (new RadioStation (103.2));foreach ($stationList as $station) { echo $station ->getFrequency (). PHP_EOL;}$stationList ->removeStation (new RadioStation (89)); // Видалить 89 станцію

Приклади на Java і Python.

Посередник (Mediator)

Вікіпедія свідчить:

Посередник – поведінковий шаблон проектування, що забезпечує взаємодію безлічі об’єктів, формуючи при цьому слабку зв’язаність, і позбавляючи об’єкти від необхідності явно посилатися один на одного.

Приклад з життя: Загальним прикладом буде, коли ви говорите з кимось по мобільнику, то між вами і співрозмовником знаходиться мобільний оператор. Тобто сигнал передається через нього, а не безпосередньо. У цьому прикладі оператор – посередник.

Простими словами: Шаблон посередник має на увазі додавання стороннього об’єкту (посередника) для управління взаємодією між двома об’єктами (колегами). Шаблон допомагає зменшити зв’язаність (coupling) класів, які спілкуються один з одним, адже тепер вони не повинні знати про реалізації своїх співрозмовників.

Розберемо приклад у коді. Простий приклад: чат (посередник), в якому користувачі (колеги) відправляють один одному повідомлення.

Спочатку у нас є посередник ChatRoomMediator:

interface ChatRoomMediator { public function showMessage (User $user, string $message);}// Посредникclass ChatRoom implements ChatRoomMediator{ public function showMessage (User $user, string $message) { $time = date ('M d, y H:i'); $sender = $user ->getName ();
echo $time . '[' . $sender . ']:' . $message; }}

Потім у нас є наші User (колеги):

class User { protected $name; protected $chatMediator; public function __construct (string $name, ChatRoomMediator $chatMediator) { $this ->name = $name; $this ->chatMediator = $chatMediator; } public function getName (){ return $this ->name; } public function send ($message) { $this ->chatMediator ->showMessage ($this, $message); }}

Приклад використання :

$mediator = new ChatRoom ();$john = new User ('John Doe', $mediator);$jane = new User ('Jane Doe', $mediator);$john ->send ('Привіт!');$jane ->send ('Привіт!');// Виведення// Feb 14, 10: 58 [John]: Привіт!
// Feb 14, 10: 58 [Jane]: Привіт!

Приклади на Java і Python.

Хранитель (Memento)

Вікіпедія свідчить:

Хранитель – поведінковий шаблон проектування, що дозволяє, не порушуючи інкапсуляцію, зафіксувати і зберегти внутрішній стан об’єкту так, щоб пізніше відновити його в цьому стані.

Приклад з життя: Як приклад можна привести калькулятор (творець), у якого будь-яка остання виконана операція зберігається в пам’яті (хранитель), щоб ви могли знову викликати її за допомогою якихось кнопок (опікун).

Простими словами: Шаблон хранитель фіксує і зберігає поточний стан об’єкту, щоб воно легко відновлювалося.

Звернемося до коду. Візьмемо наш приклад текстового редактора, який час від часу зберігає стан, який ви можете відновити.

Спочатку у нас є наш об’єкт EditorMemento, який може містити стан редактора :

class EditorMemento{ protected $content; public function __construct (string $content) { $this ->content = $content; } public function getContent (){ return $this ->content; }}

Потім у нас є наш Editor (творець)який використовуватиме об’єкт хранитель:

class Editor{ protected $content = ''; public function type (string $words) { $this ->content = $this ->content . ' ' . $words; } public function getContent (){ return $this ->content; } public function save (){ return new EditorMemento ($this ->content); } public function restore (EditorMemento $memento) { $this ->content = $memento ->getContent (); }}

Приклад використання :

$editor = new Editor ();// Друкуємо що-небудь$editor ->type ('Ця перша пропозиція.');$editor ->type ('Це друге.');// Зберігаємо стан для відновлення: Ця перша пропозиція. Це друге.$saved = $editor ->save ();// Друкуємо ще$editor ->type ('І це третє.');// Висновок: Дані до сохраненияecho $editor ->getContent (); // Ця перша пропозиція. Це друге. І це третє.// Відновлення останнього збереження$editor ->restore ($saved);$editor ->getContent (); // Ця перша пропозиція. Це друге.

Приклади на Java і Python.

Спостерігач (Observer)

Вікіпедія свідчить:

Спостерігач – поведінковий шаблон проектування, також відомий як “підлеглі” (Dependents). Створює механізм у класу, який дозволяє отримувати екземпляру об’єкту цього класу сповіщення від інших об’єктів про зміну їх стану, тим самим спостерігаючи за ними.

Приклад з життя: Хороший приклад: люди, що шукають роботу, підписуються на публікації на сайтах вакансій і отримують повідомлення, коли з’являються вакансії, які пасують за параметрами.

Простими словами: Шаблон визначає залежність між об’єктами, щоб при зміні стану одного з них залежні від нього дізнавалися про це.

Звернемося до коду. Наводячи наш приклад. Спочатку у нас є JobSeeker, які шукають роботи JobPost і мають бути повідомлені про її появу:

class JobPost{ protected $title; public function __construct (string $title) { $this ->title = $title; } public function getTitle (){ return $this ->title; }}class JobSeeker implements Observer{ protected $name; public function __construct (string $name) { $this ->name = $name; } public function onJobPosted (JobPost $job) { // Робимо щось з публікаціями вакансій echo 'Привіт '. $this ->name . '! З'явилася нова робота: '. $job ->getTitle (); }}

Потім ми робимо публікації JobPostings на які претенденти можуть підписуватися:

class JobPostings implements Observable{ protected $observers =[]; protected function notify (JobPost $jobPosting) {
foreach ($this ->observers as $observer) { $observer ->onJobPosted ($jobPosting); } } public function attach (Observer $observer) { $this ->observers[] = $observer; } public function addJob (JobPost $jobPosting) { $this ->notify ($jobPosting); }}

Приклад використання :

// Створюємо претендентів$johnDoe = new JobSeeker ('John Doe');$janeDoe = new JobSeeker ('Jane Doe');// Створюємо публікацію і додаємо передплатника$jobPostings = new JobPostings ();$jobPostings ->attach ($johnDoe);$jobPostings ->attach ($janeDoe);// Додаємо нову роботу і дивимося чи отримає претендент повідомлення$jobPostings ->addJob (new JobPost ('Software Engineer'));// Висновок// Привіт John Doe! З'явилася нова робота: Software Engineer
// Привіт Jane Doe! З'явилася нова робота: Software Engineer

Приклади на Java і Python.

Відвідувач (Visitor)

Вікіпедія свідчить:

Відвідувач – поведінковий шаблон проектування, що описує операцію, яка виконується над об’єктами інших класів. При зміні visitor немає необхідності змінювати обслуговувані класи.

Приклад з життя: Туристи зібралися в Дубай. Спочатку їм потрібний спосіб потрапити туди (віза). Після прибуття вони відвідуватимуть будь-яку частину міста, не запитуючи дозволу ходити де надумається. Просто скажіть їм про яке-небудь місце – і туристи можуть там побувати. Шаблон відвідувач допомагає додавати місця для відвідування.

Простими словами: Шаблон відвідувач дозволяє додавати майбутні операції для об’єктів без їх модифікування.

Перейдемо до прикладів у коді. Візьмемо зоопарк: у нас є декілька видів Animal, і нам треба послухати видавані ними звуки.

// Посещаемыйinterface Animal{ public function accept (AnimalOperation $operation);}// Посетительinterface AnimalOperation{ public function visitMonkey (Monkey $monkey); public function visitLion (Lion $lion); public function visitDolphin (Dolphin $dolphin);}

Потім у нас є реалізація для тварин:

class Monkey implements Animal{ public function shout (){ echo 'У-у-а-а!'; } public function accept (AnimalOperation $operation) { $operation ->visitMonkey ($this); }}class Lion implements Animal{ public function roar (){ echo 'рррр!'; } public function accept (AnimalOperation $operation) { $operation ->visitLion ($this); }}class Dolphin implements Animal{ public function speak (){
echo '*звуки дельфіна*!'; // Я поняття не маю як описати їх звуки } public function accept (AnimalOperation $operation) { $operation ->visitDolphin ($this); }}

Давайте реалізуємо відвідувача:

class Speak implements AnimalOperation{ public function visitMonkey (Monkey $monkey) { $monkey ->shout (); } public function visitLion (Lion $lion) { $lion ->roar (); } public function visitDolphin (Dolphin $dolphin) { $dolphin ->speak (); }}

Приклад використання :

$monkey = new Monkey ();$lion = new Lion ();$dolphin = new Dolphin ();$speak = new Speak ();$monkey ->accept ($speak); // У-у-а-а! $lion ->accept ($speak); // Рррр!
$dolphin ->accept ($speak); // *звуки дельфіна*!

Це можна було зробити просто за допомогою ієрархії спадкоємства, але тоді довелося б модифікувати тварин при кожному додаванні до них нових дій. А тут міняти їх не треба. Наприклад, ми можемо додати тваринам стрибки, просто створивши нового відвідувача:

class Jump implements AnimalOperation{ public function visitMonkey (Monkey $monkey) { echo 'Стрибає на 20 футів!'; } public function visitLion (Lion $lion) { echo 'Стрибає на 7 футів!'; } public function visitDolphin (Dolphin $dolphin) { echo 'З'явився над водою і зник!'; }}

Приклад використання :

$jump = new Jump ();$monkey ->accept ($speak); // У-у-а-а!
$monkey ->accept ($jump); // Стрибає на 20 футів!$lion ->accept ($speak); // Рррр!$lion ->accept ($jump); // Стрибає на 7 футів!$dolphin ->accept ($speak); // *звуки дельфінів*!$dolphin ->accept ($jump); // З'явився над водою і зник

Приклади на Java і Python.

Стратегія (Strategy)

Вікіпедія свідчить:

Стратегія – поведінковий шаблон проектування, призначений для визначення сімейства алгоритмів, інкапсуляції кожного з них і забезпечення їх взаємозамінюваності. Це дозволяє вибирати алгоритм шляхом визначення відповідного класу. Шаблон Strategy дозволяє міняти вибраний алгоритм незалежно від об’єктів-клієнтів, які його використовують.

Приклад з життя: Візьмемо приклад з бульбашковим сортуванням. Ми його реалізували, але із зростанням об’ємів даних сортування робота стала виконуватися дуже повільно. Тоді ми зробили швидке сортування. Алгоритм працює швидше на великих об’ємах, але на маленьких він дуже повільний. Тоді ми реалізували стратегію, при якій для маленьких об’ємів даних використовується бульбашкове сортування, а для великих об’ємів – швидке.

Простими словами: Шаблон стратегія дозволяє перемикатися між алгоритмами або стратегіями залежно від ситуації.

Перейдемо до коду. Візьмемо наш приклад. Спочатку у нас є наша SortStrategy і різні її реалізації:

interface SortStrategy{ public function sort (array $dataset): array;}class BubbleSortStrategy implements SortStrategy{
public function sort (array $dataset): array { echo "Сортування бульбашкою"; // Сортування return $dataset; }}class QuickSortStrategy implements SortStrategy{ public function sort (array $dataset): array { echo "Швидке сортування"; // Сортування return $dataset; }}

І у нас є Sorter, який збирається використати якусь стратегію:

class Sorter{ protected $sorter; public function __construct (SortStrategy $sorter) { $this ->sorter = $sorter; } public function sort (array $dataset): array { return $this ->sorter ->sort ($dataset); }}

Приклад використання :

$dataset =[1, 5, 4, 3, 2, 8];$sorter = new Sorter (new BubbleSortStrategy());
$sorter ->sort ($dataset); // Висновок: Сортування бульбашкою$sorter = new Sorter (new QuickSortStrategy());$sorter ->sort ($dataset); // Висновок: Швидке сортування

Приклади на Java і Python.

Стан (State)

Вікіпедія свідчить:

Стан – поведінковий шаблон проектування. Використовується в тих випадках, коли під час виконання програми об’єкт повинен міняти свою поведінку залежно від свого стану.

Приклад з життя: Припустимо, в графічному редакторові ви вибрали пензлик. Він міняє свою поведінку залежно від налаштування кольору, тобто малює лінію вибраного кольору.

Простими словами: Шаблон дозволяє міняти поведінку класу при зміні стану.

Перейдемо до прикладів у коді. Візьмемо приклад текстового редактора, він дозволяє вам міняти стан надрукованого тексту. Наприклад, якщо у вас вибраний курсив, то він писатиме курсивом і так далі.

Спочатку у нас є інтерфейс WritingState і декілька його реалізацій:

interface WritingState{ public function write (string $words);}class UpperCase implements WritingState{ public function write (string $words) { echo strtoupper ($words); }}class LowerCase implements WritingState{ public function write (string $words) { echo strtolower ($words); }}class Default implements WritingState{ public function write (string $words) { echo $words; }}

Потім TextEditor:

class TextEditor{
protected $state; public function __construct (WritingState $state) { $this ->state = $state; } public function setState (WritingState $state) { $this ->state = $state; } public function type (string $words) { $this ->state ->write ($words); }}

Приклад використання :

$editor = new TextEditor (new Default());$editor ->type ('Перший рядок');$editor ->setState (new UpperCase());$editor ->type ('Другий рядок');$editor ->type ('Третій рядок');$editor ->setState (new LowerCase());$editor ->type ('Четвертий рядок');$editor ->type ('П'ятий рядок');// Output:// Перший рядок// ДРУГИЙ РЯДОК// ТРЕТІЙ РЯДОК// четвертий рядок// п'ятий рядок

Приклади на Java і Python.

Шаблонний метод (Template Method)

Вікіпедія свідчить:

Шаблонний метод – поведінковий шаблон проектування, що визначає основу алгоритму і дозволяє спадкоємцям перевизначати деякі кроки алгоритму, не змінюючи його структуру в цілому.

Приклад з життя: Припустимо, ви зібралися будувати будинки. Етапи будуть такими:

  1. Підготовка фундаменту.
  2. Зведення стін.
  3. Настил даху.
  4. Настил перекриттів.

Порядок етапів ніколи не міняється. Ви не настелите дах до зведення стін і т. д. Але кожен етап модифікується: стіни, наприклад, можна звести з дерева, цеглини або газобетону.

Простими словами: Шаблонний метод визначає каркас виконання певного алгоритму, але реалізацію самих етапів делегує дочірнім класам.

Звернемося до коду. Припустимо, у нас є програмний інструмент, що дозволяє тестувати, проводити контроль якості коду, виконувати складання, генерувати звіти складання (звіти про покриття коду, про якість коду і т. д.), а також розгортати додаток на тестовому сервері.

Спочатку у нас є наш Builder, який описує скелет для побудови алгоритму :

abstract class Builder{ // Шаблонний метод final public function build (){ $this ->test (); $this ->lint (); $this ->assemble (); $this ->deploy (); } abstract public function test (); abstract public function lint (); abstract public function assemble (); abstract public function deploy ();}

Потім у нас є його реалізації:

class AndroidBuilder extends Builder{ public function test (){ echo 'Запуск Android тестів'; } public function lint (){ echo 'Копіювання Android коду'; } public function assemble (){ echo 'Android складання'; } public function deploy (){ echo 'Розгортання складання на сервері'; }}class IosBuilder extends Builder{ public function test (){ echo 'Запуск iOS тестів'; } public function lint (){ echo 'Копіювання iOS коду'; } public function assemble (){ echo 'iOS складання'; } public function deploy (){ echo 'Розгортання складання на сервері'; }}

Приклад використання :

$androidBuilder = new AndroidBuilder ();$androidBuilder ->build ();// Висновок:
// Запуск Android тестів// Копіювання Android кода// Android складання// Розгортання складання на сервері$iosBuilder = new IosBuilder ();$iosBuilder ->build ();// Висновок:// Запуск iOS тестів// Копіювання iOS коду// iOS складання// Розгортання складання на сервері

Приклади на Java і Python.

Переклад статті “Design Patterns for Humans”

Київ, Харків, Одеса, Дніпро, Запоріжжя, Кривий Ріг, Вінниця, Херсон, Черкаси, Житомир, Хмельницький, Чернівці, Рівне, Івано-Франківськ, Кременчук, Тернопіль, Луцьк, Ужгород, Кам'янець-Подільський, Стрий - за статистикою саме з цих міст програмісти найбільше переїжджають працювати до Львова. А Ви розглядаєте relocate?


Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *