Сім хороших об’єктно-орієнтованих звичок при програмуванні на PHP (исходники)

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

Тим не менше, навіть без спеціальних об’єктно-орієнтованих мовних конструкцій програміст може реалізувати в PHP-коді деякі принципи ООП. Подібне змішання парадигм (процедурний мову з ГО-елементами) дещо ускладнює роботу програміста і може ускладнити читання програмного коду. ГО-конструкції в PHP-коді – дозволяють створювати і застосовувати класи, будувати відносини між класами з використанням успадкування, визначати інтерфейси – суттєво спрощують написання програмного коду, відповідного методикам ООП.


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


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


Незважаючи на те, що загальна кількість “корисних звичок” при побудові ГО-програм істотно перевищує число 7, описувані в даній статті звички – це саме те, що необхідно вам для приведення свого програмного коду у відповідність з базовими критеріями ООП. Ці сім звичок утворюють стійкий фундамент, на якому ви зможете будувати свої наступні ГО-підходи та створювати програмне забезпечення, яке буде досить простим в обслуговуванні і в розширенні. Ці звички націлені на кілька ключових аспектів модульності.


Отже, сім хороших об’єктно-орієнтованих звичок при програмуванні на PHP:



  1. Будьте скромні.
  2. Будьте хорошим сусідом.
  3. Не дивіться на Медузу Горгону.
  4. Застосовуйте саме слабке зв’язування.
  5. Забезпечте високе зчеплення.
  6. Підтримуйте сімейність.
  7. Мисліть шаблонами.

Будьте скромні


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


Внаслідок безлічі причин безпосереднє виставлення полів у вигляді public є поганою звичкою; і найважливіша з цих причин наступна: ви позбавляєте себе можливості щось змінити в своїй реалізації у разі потреби. Концепції ООП використовуються для того, щоб ізолювати зміни; інкапсуляція грає тут центральну роль – вона гарантує, що будь-які внесені вами зміни не будуть вірулентними за своєю природою. Вірулентні зміни починаються з малого, наприклад, з перетворення трьохелементної масиву в масив, що містить всього два елементи. Раптово ви виявляєте, що для того, щоб адаптуватися до цього, здавалося б, тривіального зміни, вам доводиться вносити в свій код все більше і більше інших змін.


Один простий спосіб для переходу до приховування своєї інформації полягає в тому, щоб залишати поля в статусі private і виставляти їх за допомогою public методів-аксессор, які ведуть себе як вікна у вашому будинку. Замість того щоб відкривати назовні всю стіну, ви використовуєте всього одне або два вікна.


Використання public-аксессор замість безпосереднього виставлення полів дозволяє вам міняти свою реалізацію “за завісою”. Крім того, це дозволяє вам продовжити використання своєї базової реалізації за допомогою перевизначення реалізації аксессор, щоб він зміг робити щось відмінне від поведінки свого батька. Це також дозволяє будувати абстрактні реалізації, яке відсувають фактичну реалізацію до моменту створення класів, перевизначати базову реалізацію.


Погана звичка: виставлення полів як public


У прикладі “поганого” коду в лістингу 1 аксессор не застосовуються, а поля об’єкта Person виставлені безпосередньо як поля public. Хоча така поведінка і заманливо, особливо у випадку “легковагих” об’єктів даних, воно істотно обмежує ваші можливості.


Лістинг 1. Погана звичка: виставлення полів як public




<?php
class Person
{
public $prefix;
public $givenName;
public $familyName;
public $suffix;
}
$person = new Person();
$person->prefix = “Mr.”;
$person->givenName = “John”;
echo($person->prefix);
echo($person->givenName);
?>

Якщо в об’єкті небудь змінюється, то будь-який код, який використовує його, також повинен змінитися. Наприклад, якщо ім’я, прізвище та інші атрибути певної людини необхідно інкапсулювати в об’єкт PersonName, То для адаптації до цієї зміни вам доведеться модифікувати весь свій код.


Гарна звичка: використання public-аксессор


При використанні хороших ГО-звичок (див. лістинг 2) той же самий об’єкт тепер має поля типу private (замість полів public), і ці поля private з дотриманням заходів обережності виставлені зовнішньому світу за допомогою методів get і set, Так званих методів-акессоров. Тепер ці аксессор забезпечують публічний спосіб отримання інформації від вашого класу PHP. У разі будь-яких змін у вашій реалізації це суттєво зменшить ймовірність того, що вам доведеться змінювати весь код, що використовує цей клас.


Лістинг 2. Гарна звичка: використання public-аксессор




<?php
class Person
{
private $prefix;
private $givenName;
private $familyName;
private $suffix;

public function setPrefix($prefix)
{
$this->prefix = $prefix;
}

public function getPrefix()
{
return $this->prefix;
}

public function setGivenName($gn)
{
$this->givenName = $gn;
}

public function getGivenName()
{
return $this->givenName;
}

public function setFamilyName($fn)
{
$this->familyName = $fn;
}

public function getFamilyName()
{
return $this->familyName;
}

public function setSuffix($suffix)
{
$this->suffix = $suffix;
}

public function getSuffix()
{
return $suffix;
}

}
$person = new Person();
$person->setPrefix(“Mr.”);
$person->setGivenName(“John”);
echo($person->getPrefix());
echo($person->getGivenName());
?>


На перший погляд може здатися, що це суттєво збільшує обсяг роботи, особливо на фронтальній частині. Слід, однак, відзначити, що в більшості випадків використання хороших ГО-звичок в кінцевому рахунку окупається, оскільки істотно спрощує майбутні зміни.


У версії коду, показаної в лістингу 3, я змінив внутрішню реалізацію, використавши асоціативний масив для окремих частин імені. В ідеалі мені слід було б приділити більше уваги обробки помилок і дотримуватися великої обережності, зокрема, перевіряти елементи на існування, однак у цього прикладу дещо інші цілі: я хочу показати, що код, що використовує мій клас, не потребує змін – Він знаходиться у блаженному невіданні про зміни в моєму класі. Пам’ятайте, що причина для прийняття хороших ГО-звичок полягає в тому, щоб ретельно інкапсулювати зміни і таким чином поліпшити розширюваність і сопровождаемость коду.


Лістинг 3. Інший різновид цієї гарної звички з іншої внутрішньої реалізацією




<?php
class Person
{
private $personName = array();

public function setPrefix($prefix)
{
$this->personName[“prefix”] = $prefix;
}

public function getPrefix()
{
return $this->personName[“prefix”];
}

public function setGivenName($gn)
{
$this->personName[“givenName”] = $gn;
}

public function getGivenName()
{
return $this->personName[“givenName”];
}
/* etc… */
}
/*
* Even though the internal implementation changed, the code here stays exactly
* the same. The change has been encapsulated only to the Person class.
*/
$person = new Person();
$person->setPrefix(“Mr.”);
$person->setGivenName(“John”);
echo($person->getPrefix());
echo($person->getGivenName());
?>






Будьте хорошим сусідом


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


Погана звичка: відсутність обробки помилок


Розглянемо показаний в лістингу 4 приклад, в якому приймаються деякі аргументи і повертається об’єкт Person з деякими заповненими значеннями. У методі parsePersonName() відсутня будь перевірка на предмет того, чи не має надавана змінна $val стану null і чи не є вона рядком нульової довжини або рядком в підтримуваному форматі. Метод parsePersonName() не повертає об’єкт Person, Але повертає null. Адміністраторам або програмістам, які використовують цей метод, доведеться надовго замислитися і, як мінімум, зайнятися введенням контрольних точок і налагодженням цього PHP-скрипта.


Лістинг 4. Погана звичка: відсутність видачі або обробки помилок




class PersonUtils
{
public static function parsePersonName($format, $val)
{
if (strpos(“,”, $val) > 0) {
$person = new Person();
$parts = split(“,”, $val); // Assume the value is last, first
$person->setGivenName($parts[1]);
$person->setFamilyName($parts[0]);
}
return $person;
}
}

Метод parsePersonName() в лістингу 4 можна змінити таким чином, щоб ініціалізувати об’єкт Person за межами умови if. Це гарантує, що ви завжди будете отримувати об’єкт Person в допустимому стані. Однак при цьому ви отримуєте об’єкт Person без встановлених властивостей, що ненабагато поліпшує ваше положення.


Гарна звичка: кожен модуль сам обробляє свої помилки


Замість того щоб змушувати своїх “викликають” будувати здогади, подбайте заздалегідь про перевірку аргументів. Якщо не встановлене значення змінної може призвести до недостовірних результатів, перевірте цю змінну і відійти виключення InvalidArgumentException. Якщо рядок не може бути порожньою або повинна бути представлена ​​в певному форматі, перевірте її на відповідність цього формату і відійти виняток. У лістингу 5 показано, як створювати свої власні виключення, а також продемонстровані нові умови в методі parsePerson(), Які здійснюють деякі елементарні перевірки.


Лістинг 5. Гарна звичка: видача помилок




<?php
class InvalidPersonNameFormatException extends LogicException {}
class PersonUtils
{
public static function parsePersonName($format, $val)
{
if (! $format) {
throw new InvalidPersonNameFormatException(“Invalid PersonName format.”);
}
if ((! isset($val)) // strlen($val) == 0) {
throw new InvalidArgumentException(“Must supply a non-null value to parse.”);
}
}
}
?>

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







Не дивіться на Медузу Горгону


Коли я вперше вивчав концепції ООП, у мене були певні сумніви щодо того, чи є інтерфейси дійсно корисними. Мій колега запропонував наступну аналогію: не використовувати інтерфейси – Це те ж саме, що дивитися в обличчя Медузи Горгони. Згідно старогрецької міфології, Медуза Горгона – це жіноча істота зі зміями замість волосся. Будь-яка людина, який дивився на неї безпосередньо, перетворювався на камінь. Персей, який вбив Медузу, зміг протистояти їй, дивлячись на її відображення в своєму відполірованому щиті, і таким чином уникнувши перетворення в камінь.


Інтерфейси – це ваше дзеркало при поводженні з Медуза Горгона. Якщо ви застосовуєте спеціалізовану, “негнучку” реалізацію, то в разі зміни цієї реалізації ваш код також повинен буде змінитися. Безпосереднє використання реалізацій обмежує перелік доступних вам варіантів, оскільки, образно кажучи, ви звернули свої класи в камінь.


Погана звичка: відсутність інтерфейсів


У прикладі в лістингу 6 об’єкт Person завантажується з бази даних. Зокрема, здійснюється прийом імені людини (Person) і повернення об’єкта Person у відповідну базу даних.


Лістинг 6. Погана звичка: відсутність інтерфейсів




<?php
class DBPersonProvider
{
public function getPerson($givenName, $familyName)
{
/* go to the database, get the person… */
$person = new Person();
$person->setPrefix(“Mr.”);
$person->setGivenName(“John”);
return $person;
}
}
/* I need to get person data… */
$provider = new DBPersonProvider();
$person = $provider->getPerson(“John”, “Doe”);
echo($person->getPrefix());
echo($person->getGivenName());
?>

Код для завантаження Person з бази даних працює чудово до тих пір, поки в навколишньому середовищі нічого не змінюється. Наприклад, завантаження Person з бази даних може ефективно задовольняти потреби першої версії додатка, проте в його другій версії вам, можливо, доведеться додати можливість завантаження інформації з Web-сервісу. По суті, ваш клас “скам’янів”, оскільки він безпосередньо використовує клас реалізації і не розрахований на зміни.


Гарна звичка: використання інтерфейсів


У лістингу 7 показаний приклад коду, який не потребує змін у разі появи та реалізації нових способів завантаження користувачів. У прикладі показаний інтерфейс з ім’ям PersonProvider, Який оголошує єдиний метод. Якщо який-небудь код використовує інтерфейс PersonProvider, То цей код буде ізольований від безпосереднього використання класів реалізації. Замість цього зазначений код буде використовувати інтерфейс PersonProvider, Як ніби це реальний об’єкт.


Лістинг 7. Гарна звичка: використання інтерфейсів




<?php
interface PersonProvider
{
public function getPerson($givenName, $familyName);
}
class DBPersonProvider implements PersonProvider
{
public function getPerson($givenName, $familyName)
{
/* pretend to go to the database, get the person… */
$person = new Person();
$person->setPrefix(“Mr.”);
$person->setGivenName(“John”);
return $person;
}
}
class PersonProviderFactory
{
public static function createProvider($type)
{
if ($type == “database”)
{
return new DBPersonProvider();
} else {
return new NullProvider();
}
}
}
$config = “database”;
/* I need to get person data… */
$provider = PersonProviderFactory::createProvider($config);
$person = $provider->getPerson(“John”, “Doe”);
echo($person->getPrefix());
echo($person->getGivenName());
?>

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


За допомогою шаблону Factory ви можете створити екземпляр класу реалізації, який і реалізує ваш інтерфейс. Відповідно до прийнятих угод, метод factory починається зі слова create і повертає інтерфейс. Він може прийняти будь-які аргументи, необхідні для вашого шаблону factory, Щоб з’ясувати, який клас реалізації є коректним для повернення.


У лістингу 7 метод createProvider() просто приймає значення $type. Якщо змінній $type присвоюється значення database, То factory повертає екземпляр DBPersonProvider. Будь-яка нова реалізація для завантаження даних про людей з якого-небудь сховища не зажадає якихось змін в класі, який використовує шаблон factory і інтерфейс. Клас DBPersonProvider реалізує інтерфейс PersonProvider і містить в собі фактичну реалізацію методу getPerson().







Застосовуйте саме слабке зв’язування


Слабке зв’язування модулів є досить гарним прийомом; слабке зв’язування – це одна з властивостей, які дозволяють інкапсулювати зміни. Дві розглянуті вище звички – “скромність” і “використання інтерфейсу для роботи з Медуза Горгона “- допомагають створювати саме слабо пов’язані модулі. Щоб домогтися слабкого зв’язування своїх класів, виробіть звичку до ослаблення їх залежностей.


Погана звичка: сильне зв’язування


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


Лістинг 8. Погана звичка: сильне зв’язування




<?php
require_once “./AddressFormatters.php”;
class Address
{
private $addressLine1;
private $addressLine2;
private $city;
private $state; // or province…
private $postalCode;
private $country;
public function setAddressLine1($line1)
{
$this->addressLine1 = $line1;
}
/* accessors, etc… */
public function getCountry()
{
return $this->country;
}
public function format($type)
{
if ($type == “inline”) {
$formatter = new InlineAddressFormatter();
} else if ($type == “multiline”) {
$formatter = new MultilineAddressFormatter();
} else {
$formatter = new NullAddressFormatter();
}
return $formatter->format($this->getAddressLine1(),
$this->getAddressLine2(),
$this->getCity(), $this->getState(), $this->getPostalCode(),
$this->getCountry());
}
}
$addr = new Address();
$addr->setAddressLine1(“123 Any St.”);
$addr->setAddressLine2(“Ste 200”);
$addr->setCity(“Anytown”);
$addr->setState(“AY”);
$addr->setPostalCode(“55555-0000”);
$addr->setCountry(“US”);
echo($addr->format(“multiline”));
echo(”
“);
echo($addr->format(“inline”));
echo(”
“);
?>

Код, який викликає метод format() в об’єкті Address, Може виглядати чудово: все, що йому потрібно зробити – використовувати клас Address і викликати метод format(). Завдання самого класу Address дещо складніше. Щоб здійснити форматування належним чином, йому необхідно знати про різних використовуваних “форматер”. Це обмежує можливості повторного використання об’єкта Address ким ще, особливо якщо цей “хтось” не зацікавлений у використанні класів formatter в методі format(). Хоча код, що використовує клас Address, Не має великого числа залежностей, у самого класу Address досить багато залежностей, при тому, що йому, ймовірно, слід було б бути простим об’єктом даних.


Клас Address сильно пов’язаний з класами реалізації, які “знають”, як форматувати об’єкт Address.


Гарна звичка: слабке зв’язування між об’єктами


При побудові гарних ГО-проектів необхідно дотримуватися концепції “поділу відповідальності” (Separation of Concerns, SoC). У відповідності з цією концепцією об’єкти розділяються по покладеної на них відповідальності, що суттєво послаблює зв’язування між ними. У вихідної ситуації на клас Address покладається відповідальність за здійснення форматування. Ймовірно, це не дуже хороший підхід. Замість цього класу Address слід було б піклуватися про частини адреси, в той час як за належне форматування адреси мав би відповідати відповідний форматер (formatter).


Як показано в лістингу 9, код, який раніше форматувати адресу, тепер переміщений в інтерфейси, в класи реалізації і в factory – відповідно зі звичкою до “використанню інтерфейсів”. Тепер клас AddressFormatUtils відповідає за створення форматер і за форматування адреси. Об’єкт Address тепер може бути використаний будь-яким іншим об’єктом, без будь-якого занепокоєння про визначення вимог до форматер.


Лістинг 9. Гарна звичка: слабке зв’язування між об’єктами




<?php
interface AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country);
}
class MultiLineAddressFormatter implements AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country)
{
return sprintf(“%s
%s
%s, %s %s
%s”,
$addressLine1, $addressLine2, $city, $state, $postalCode, $country);
}
}
class InlineAddressFormatter implements AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country)
{
return sprintf(“%s %s, %s, %s %s %s”,
$addressLine1, $addressLine2, $city, $state, $postalCode, $country);
}
}
class AddressFormatUtils
{
public static function formatAddress($type, $address)
{
$formatter = AddressFormatUtils::createAddressFormatter($type);

return $formatter->format($address->getAddressLine1(),
$address->getAddressLine2(),
$address->getCity(), $address->getState(),
$address->getPostalCode(),
$address->getCountry());
}

private static function createAddressFormatter($type)
{
if ($type == “inline”) {
$formatter = new InlineAddressFormatter();
} else if ($type == “multiline”) {
$formatter = new MultilineAddressFormatter();
} else {
$formatter = new NullAddressFormatter();
}
return $formatter;
}
}
$addr = new Address();
$addr->setAddressLine1(“123 Any St.”);
$addr->setAddressLine2(“Ste 200”);
$addr->setCity(“Anytown”);
$addr->setState(“AY”);
$addr->setPostalCode(“55555-0000”);
$addr->setCountry(“US”);
echo(AddressFormatUtils::formatAddress(“multiline”, $addr));
echo(”
“);
echo(AddressFormatUtils::formatAddress(“inline”, $addr));
echo(”
“);
?>


Зворотний бік цього підходу полягає в тому, що при будь-якому використанні шаблонів зростає кількість артефактів (класів, файлів). Тим не менше ця тенденція компенсується зменшенням обсягу супроводу в кожному класі, причому ступінь цієї компенсації значно зростає при досягненні належного рівня багаторазового використання.







Забезпечте високе зчеплення


ГО-проекти з т.зв. “Високим зчепленням” (high cohesion) відрізняються сфокусованість і організованістю у вигляді модулів з глибинною спорідненістю. Знання “відповідальності” (див. попередній розділ) дозволяє організувати функції і класи таким чином, щоб вони володіли високим зчепленням.


Погана звичка: низьке зчеплення


Низьке зчеплення проекту означає, що його класи і методи згруповані неналежним чином. Для опису класів і методів, які об’єднані один з одним, але при цьому мають низьке зчеплення, часто використовується термін спагетті-код. Приклад спагетті-коду показаний в лістингу 10. Порівняно універсальний (generic) клас Utils використовує кілька різних об’єктів і має декілька залежностей. Він робить “всього потроху”, що істотно ускладнює його повторне використання.


Лістинг 10. Погана звичка: низьке зчеплення




<?php
class Utils
{
public static function formatAddress($formatType, $address1,
$address2, $city, $state)
{
return “some address string”;
}

public static function formatPersonName($formatType, $givenName,
$familyName)
{
return “some person name”;
}

public static function parseAddress($formatType, $val)
{
// real implementation would set values, etc…
return new Address();
}

public static function parseTelephoneNumber($formatType, $val)
{
// real implementation would set values, etc…
return new TelephoneNumber();
}
}
?>


Гарна звичка: високе зчеплення


Високе зчеплення проекту означає, що споріднені класи і методи об’єднані в групи. Якщо методи і класи володіють високим зчепленням, ви зможете легко виділити їх із складу групи без шкоди для всього проекту. Проекти з високим зчепленням створюють умови для ослаблення зв’язності. У лістингу 11 показана більш ефективна організація методів в класи. Клас AddressUtils містить методи для роботи з класами Address, Завдяки чому забезпечується високе зчеплення методів, що мають відношення до адресою. Аналогічно, клас PersonUtils містить методи, які мають справу тільки з об’єктами Person. Ці два нових класи, методи усередині яких мають високе зчеплення, самі володіють низькою взаємною зв’язністю, оскільки можуть бути використані абсолютно незалежно один від одного.


Listing 11. Гарна звичка: високе зчеплення




<?php
class AddressUtils
{
public static function formatAddress($formatType, $address1,
$address2, $city, $state)
{
return “some address string”;
}

public static function parseAddress($formatType, $val)
{
// real implementation would set values, etc…
return new Address();
}

}
class PersonUtils
{
public static function formatPersonName($formatType, $givenName,
$familyName)
{
return “some person name”;
}

public static function parsePersonName($formatType, $val)
{
// real implementation would set values, etc…
return new PersonName();
}
}
?>






Підтримуйте сімейність


Учасникам груп розробки програмного забезпечення, у яких я є технічним керівником або архітектором, я часто повторюю, що основний ворог ГО-мов – операція “копіювати-вставити”. Ніщо інше не здатне завдати більшої шкоди, ніж копіювання коду з попереднього файлу в наступний файл – без заздалегідь підготовленого ГО-проекту. Кожен раз, коли ви відчуваєте спокусу скопіювати код з одного класу в інший, зупиніться і подумайте, яким чином ви могли б використовувати ієрархії класів для реалізації подібних або ідентичних функціональних можливостей. Ви виявите, що у більшості випадків при наявності гарного проекту в копіюванні коду немає абсолютно ніякої необхідності.


Погана звичка: відсутність використання ієрархій класів


У лістингу 12 показаний простий приклад часткових класів. У цих класах застосовуються дублюються поля і методи – що не дуже добре в довгостроковій перспективі, коли, можливо, доведеться модифікувати дане додаток. Якщо в класі Person є дефект, то найімовірніше, аналогічний дефект є і в класі Employee, Оскільки він, по-видимому, створений копіюванням першого класу (або навпаки).


Лістинг 12. Погана звичка: відсутність використання ієрархій класів




<?php
class Person
{
private $givenName;
private $familyName;
}
class Employee
{
private $givenName;
private $familyName;
}
?>

Виробити звичку до використання спадкування важко, оскільки у багатьох випадках аналіз, необхідний для побудови належних моделей успадкування, може забрати багато часу. І навпаки, використання Ctrl+C і Ctrl+V для побудови нової реалізації займає всього декілька секунд. Слід, однак, відзначити, що зазвичай витрачений час окупається досить швидко на етапі супроводу, який фактично займає більшу частину життєвого циклу додатка.


Гарна звичка: використання спадкування


У лістингу 13 показаний новий клас Employee, Що розширює клас Person. Він тепер успадковує всі загальні методи, не реалізуючи їх повторно. Крім того, в лістингу 13 показано, як використання абстрактного методу дозволяє помістити базову функціональність в базовий клас, а специфічну – розташувати всередині класу реалізації.


Лістинг 13. Гарна звичка: використання спадкування




<?php
abstract class Person
{
private $givenName;
private $familyName;

public function setGivenName($gn)
{
$this->givenName = $gn;
}

public function getGivenName()
{
return $this->givenName;
}

public function setFamilyName($fn)
{
$this->familyName = $fn;
}

public function getFamilyName()
{
return $this->familyName;
}

public function sayHello()
{
echo(“Hello, I am “);
$this->introduceSelf();
}

abstract public function introduceSelf();

}
class Employee extends Person
{
private $role;

public function setRole($r)
{
$this->role = $r;
}

public function getRole()
{
return $this->role;
}

public function introduceSelf()
{
echo($this->getRole() . ” ” . $this->getGivenName() . ” ” .
$this->getFamilyName());
}
}
?>






Мисліть шаблонами


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


Погана звичка: розгляд окремо взятих об’єктів


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



Гарна звичка: узгоджене додавання об’єктів у складі шаблонів


У загальному випадку ви мислите в шаблонах, якщо дотримуються наступні критерії:








Висновок


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



Коли ви сформуєте у себе ці звички і станете керуватися ними у своїй повсякденній діяльності, ви, ймовірно, будете приємно здивовані змінами в якості ваших додатків.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*