freeCodeCamp/guide/russian/php/polymorphism-abstract-inter.../index.md

374 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: Polymorphism with Abstract and Interface
localeTitle: Полиморфизм с абстрактным и интерфейсом
---
## Полиморфизм с абстрактным и интерфейсом
_Совместное использование и принудительное исполнение кода с помощью полиморфизма с использованием абстрактного класса и интерфейса_
Мы погрузимся глубже в объектно-ориентированное программирование и попытаемся подумать с точки зрения шаблонов проектирования для совместного использования и обеспечения соблюдения нашего кода с помощью полиморфизма.
### Абстрактный класс
Предположим, у нас есть класс Man с некоторыми свойствами ( `name` , `age` , `height` , `fav_drinks` и `fav_sports` ) и методы ( `giveFirmHandshakes` , `beStubborn` и `notPutToiletPaper` ).
```php
<?php
class Man
{
public $name;
public $age;
public $height;
public $fav_sports;
public $fav_drinks;
public function __construct($name, $age, $height)
{
$this->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
<?php
$jack = new Man('Jack', '26', '5 Feet 6 Inches');
echo sprintf('%s - %s - %s', $jack->name, $jack->age, $jack->height);
// => Jack - 26 - 5 Feet 6 Inches
```
Теперь предположим, что мы хотим добавить новый метод в этот класс, называемый isActive.
Этот метод проверяет свойство активным и возвращает соответствующее сообщение в зависимости от значения active со значением по умолчанию false. Мы можем утверждать, что это верно для тех людей, которые активны.
```php
<?php
class Man
{
public $name;
public $age;
public $height;
public $fav_sports;
public $fav_drinks;
public $active = false;
.....
.....
public function isActive()
{
if ($this->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
<?php
public function isActive()
{
if ($this->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
<?php
abstract class Man
{
.....
.....
}
```
# 2: Создайте абстрактный метод для метода, который вы хотите применить внутри абстрактного класса.
```php
<?php
abstract class Man
{
.....
.....
abstract public function isActive();
}
```
# 3: Создайте дочерний класс, расширяющий абстрактный класс.
```php
<?php
class AthleticMan extends Man
{
.....
.....
}
```
# 4: Внедрить абстрактный метод внутри дочернего класса.
```php
<?php
class AthleticMan extends Man
{
public function isActive()
{
return "I am a very active athlete.";
}
}
```
# 5: Создайте дочерний класс (НЕ абстрактный класс).
```php
<?php
$jack = new AthleticMan('Jack', '26', '5 feet 6 inches');
echo $jack->isActive();
// => I am a very active athlete.
```
Полное описание и код реализации абстрактного класса:
```php
<?php
abstract class Man
{
public $name;
public $age;
public $height;
public $fav_sports;
public $fav_drinks;
public function __construct($name, $age, $height)
{
$this->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
<?php
$ted = new Man('Ted', '30', '6 feet');
echo $ted->isActive();
// => Fatal error: Uncaught Error: Cannot instantiate abstract class Man
```
Кроме того, каждый дочерний класс абстрактного класса (класс `Man` ) должен реализовать все абстрактные методы. Отсутствие такой реализации приведет к фатальной ошибке.
```php
<?php
class LazyMan extends Man
{
}
$robert = new LazyMan('Robert', '40', '5 feet 10 inches');
echo $robert->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
<?php
interface Man
{
public function __construct($name, $age, $height);
public function giveFirmHandshakes();
public function beStubborn();
public function notPutToiletPaper();
public function isActive();
}
```
# 2: Создайте класс, реализующий интерфейс (используйте инструменты вместо расширений). Этот класс должен реализовать ВСЕ методы, определенные внутри интерфейса, включая метод конструктора.
```php
<?php
class AthleticMan implements Man
{
public $name;
public $age;
public $height;
public function __construct($name, $age, $height)
{
$this->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
<?php
$jack = new AthleticMan('Jack', '26', '5 feet 6 inches');
echo $jack->isActive();
// => I am a very active athlete.
```
С интерфейсами вам нужно иметь в виду, что:
* Методы не могут быть реализованы внутри интерфейса.
* Переменные (свойства) не могут быть определены внутри интерфейса.
* Все методы, определенные внутри интерфейса, должны быть реализованы в классе child (implementation).
* Все необходимые переменные должны быть определены внутри дочернего класса.
* Интерфейс Man наставляет свои классы реализации для реализации всех методов в интерфейсе.
Итак, что такое использование интерфейсов?
Разве мы не можем просто создать новый класс AthleticMan и создать все методы вместо реализации интерфейса?
Именно здесь _разрабатываются шаблоны проектирования_ .
Интерфейсы используются, когда есть базовый класс ( `Man` ), который хочет заставить вас делать что-либо (создайте объект, giveFirmHandshakes, beStubborn, notPutToiletPaper и проверьте, активны ли вы), но не хочет точно сказать вам, как это сделать ,
Вы можете просто начать реализацию классов с реализацией, как вы сочтете нужным.
Пока все методы реализованы, интерфейсу `Man` все равно, как это сделать.
Мы рассмотрели, как и когда использовать абстрактные классы и интерфейсы в PHP. Использование этих концепций ООП для классов с разной функциональностью, использующих один и тот же базовый «план» (абстрактный класс или интерфейс), называется полиморфизмом.