--- title: Polymorphism with Abstract and Interface localeTitle: Полиморфизм с абстрактным и интерфейсом --- ## Полиморфизм с абстрактным и интерфейсом _Совместное использование и принудительное исполнение кода с помощью полиморфизма с использованием абстрактного класса и интерфейса_ Мы погрузимся глубже в объектно-ориентированное программирование и попытаемся подумать с точки зрения шаблонов проектирования для совместного использования и обеспечения соблюдения нашего кода с помощью полиморфизма. ### Абстрактный класс Предположим, у нас есть класс Man с некоторыми свойствами ( `name` , `age` , `height` , `fav_drinks` и `fav_sports` ) и методы ( `giveFirmHandshakes` , `beStubborn` и `notPutToiletPaper` ). ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } } ``` Нам нужно указать имя, возраст и высоту, чтобы создать экземпляр этого класса, как требуется конструктору. ```php name, $jack->age, $jack->height); // => Jack - 26 - 5 Feet 6 Inches ``` Теперь предположим, что мы хотим добавить новый метод в этот класс, называемый isActive. Этот метод проверяет свойство активным и возвращает соответствующее сообщение в зависимости от значения active со значением по умолчанию false. Мы можем утверждать, что это верно для тех людей, которые активны. ```php active == true) { return "I am an active man."; } else { return "I am an idle man."; } } } $jack = new Man('Jack', '26', '5 Feet 6 Inches'); $jack->active = true; echo $jack->isActive(); // => I am an active man. $jake = new Man('Jake', '30', '6 Feet'); echo "\n" . $jake->isActive(); // => I am an idle man. ``` Что делать, если человек не просто активен или не работает? Что, если есть шкала от 1 до 4, которая измеряет, насколько активен человек (1 - холостой, 2 - слегка активный, 3 - умеренно активный, 4 - очень активный)? У нас могут быть утверждения if..elseif ... такие как: ```php active == 1) { return "I am an idle man."; } elseif ($this->active == 2) { return "I am a lightly active man."; } elseif ($this->active == 3) { return "I am a moderately active man."; } else { return "I am a very active man."; } } ``` Теперь давайте сделаем еще один шаг. Что, если активное свойство человека - это не просто целое число (1, 2, 3, 4 и т. Д.)? Что, если значение активного «атлетическое» или «ленивое»? Разве мы не должны добавлять другие инструкции elseif, которые ищут совпадение с этими строками? Для такого сценария могут использоваться абстрактные классы. С абстрактными классами вы в основном определяете класс как абстрактный и методы, которые вы хотите применять как абстрактные, без фактического ввода кода внутри этих методов. Затем вы создаете дочерний класс, расширяющий родительский абстрактный класс и реализующий абстрактные методы в этом дочернем классе. Таким образом, вы будете применять все дочерние классы для определения собственной версии абстрактных методов. Давайте посмотрим, как мы можем установить наш `isActive()` как абстрактный. # 1: Определите класс как абстрактный. ```php isActive(); // => I am a very active athlete. ``` Полное описание и код реализации абстрактного класса: ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } abstract public function isActive(); } class AthleticMan extends Man { public function isActive() { return "I am a very active athlete."; } } $jack = new AthleticMan('Jack', '26', '5 feet 6 inches'); echo $jack->isActive(); // => I am a very active athlete. ``` В этом коде вы заметите, что абстрактный абстрактный метод `isActive()` определен внутри абстрактного класса `Man` и реализуется внутри дочернего класса `AthleticMan` . Теперь класс `Man` не может быть создан непосредственно для создания объекта. ```php isActive(); // => Fatal error: Uncaught Error: Cannot instantiate abstract class Man ``` Кроме того, каждый дочерний класс абстрактного класса (класс `Man` ) должен реализовать все абстрактные методы. Отсутствие такой реализации приведет к фатальной ошибке. ```php isActive(); // => Fatal error: Class LazyMan contains 1 abstract method // => and must therefore be declared abstract or implement // => the remaining methods (Man::isActive) ``` Используя абстрактные классы, вы можете применять определенные методы, которые будут реализованы индивидуально дочерними классами. ### Интерфейс Существует еще одна концепция объектно-ориентированного программирования, которая тесно связана с абстрактными классами, называемыми интерфейсом. Единственная разница между абстрактными классами и интерфейсами заключается в том, что в абстрактных классах вы можете иметь сочетание определенных методов ( `giveFirmHandshakes()` , `isStubborn()` и т. Д.) И абстрактных методов ( `isActive()` ) внутри родительского класса, тогда как в интерфейсах, вы можете определять методы (не реализуйте) внутри родительского класса. Давайте посмотрим, как мы можем преобразовать абстрактный класс Man выше в интерфейс. # 1: Определите интерфейс со всеми методами (используйте интерфейс вместо класса). ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } public function isActive() { return "I am a very active athlete."; } } ``` # 3: Создайте исполняемый класс (AthleticMan) ```php isActive(); // => I am a very active athlete. ``` С интерфейсами вам нужно иметь в виду, что: * Методы не могут быть реализованы внутри интерфейса. * Переменные (свойства) не могут быть определены внутри интерфейса. * Все методы, определенные внутри интерфейса, должны быть реализованы в классе child (implementation). * Все необходимые переменные должны быть определены внутри дочернего класса. * Интерфейс Man наставляет свои классы реализации для реализации всех методов в интерфейсе. Итак, что такое использование интерфейсов? Разве мы не можем просто создать новый класс AthleticMan и создать все методы вместо реализации интерфейса? Именно здесь _разрабатываются шаблоны проектирования_ . Интерфейсы используются, когда есть базовый класс ( `Man` ), который хочет заставить вас делать что-либо (создайте объект, giveFirmHandshakes, beStubborn, notPutToiletPaper и проверьте, активны ли вы), но не хочет точно сказать вам, как это сделать , Вы можете просто начать реализацию классов с реализацией, как вы сочтете нужным. Пока все методы реализованы, интерфейсу `Man` все равно, как это сделать. Мы рассмотрели, как и когда использовать абстрактные классы и интерфейсы в PHP. Использование этих концепций ООП для классов с разной функциональностью, использующих один и тот же базовый «план» (абстрактный класс или интерфейс), называется полиморфизмом.