Мы можем использовать простое наследование или интерфейс вместо абстракции.
Почему мы должны использовать абстракцию в PHP? и как мы можем скрыть основные функции, используя абстракцию? Я запутался, используя абстракцию и интерфейс и наследование. Где использовать какой?
Пожалуйста, помогите понять меня.
Я думаю, что важно, во-первых, уточнить терминологию, чтобы более детально ответить на этот вопрос.
abstract
в абстрактном классе. Это также позволяет реализовать свойства и частные / защищенные методы, потому что наследование здесь действует как базовый класс, а не просто как требование.Чтобы ответить на вопрос «почему у нас есть абстрактные классы в PHP«, потому что это полезно. Сначала вы можете рассматривать их как неразрешимые идеи, но на самом деле они могут работать вместе, обеспечивая совместную полезность.
Учтите, что иногда для создания полезной реализации интерфейса недостаточно. Интерфейс может только гарантировать, что метод существует и что его подпись совместима с реализованным интерфейсом. Например, могут быть случаи, когда вы хотите предоставить реализации интерфейса по умолчанию.
interface Device {
public function input(Stream $in);
public function output(): Stream;
}
abstract class DefaultDevice implements Device {
protected $buffer = "";
public function input(Stream $in) {
$this->buffer .= $in->read(1024);
$this->process();
}
abstract protected function process();
}
Так что теперь любой класс, который расширяется DefaultDevice
можно либо отменить реализацию input
метод или нет. Это также должно реализовать process
метод, хотя интерфейс не требует этого. Это означает, что другие классы, реализующие Device
Интерфейс может быть обратно совместимым, и это остается деталью реализации.
Отделение реализации от спецификации, как правило, является ключевым атрибутом хорошо написанного программного обеспечения.
Посмотрите на Device
Сам интерфейс, как хороший пример. Мы полагаемся на input
способ принять Stream
тип и output
способ вернуть Stream
тип. поскольку Stream
сам по себе может быть интерфейсом, это означает, что любой тип, реализующий Stream
приемлемо Так что я мог создать свой собственный класс и реализовать Stream
интерфейс, не нарушая этот код.
class CustomStream implements Stream {
public function read($bytes = 1024) {
/* implementation */
}
public function write($data) {
/* implementation */
}
}
$device->input(new CustomStream); // this will not throw an error
abstract
Класс используется для предоставления набора членов-данных или методов, которые должны быть доступны для классов, которые наследуются от него, даже если базовый класс не особенно полезен (и никогда не должен создаваться самостоятельно) без унаследованной реализации.
отсюда наследование вступает во владение.
interface
с другой стороны — предоставить набор правил для реализации, которые требуют от каждого класса, который использует интерфейс, для реализации найденных в нем спецификаций. классы, реализующие один и тот же интерфейс, не должны наследоваться друг от друга, они реализуют интерфейс, поэтому их можно использовать в любом приложении, требующем такой набор функций.
Так же, как упражнение, давайте попробуем создать несколько классов для обработки геометрических фигур.
Базовый класс:
class Shape
{
public function draw()
{
}
}
Только соответствующая часть базового класса описана во фрагменте кода выше. Конечно, он должен иметь свойства для хранения своей позиции, цвета линии и т. Д. И методов (по крайней мере, конструктора).
Пара производных классов:
class Circle extends Shape
{
public function draw()
{
// the code to draw a circle
}
}
class Rectangle extends Shape
{
public function draw()
{
// the code to draw a rectangle
}
}
Можем ли мы предоставить реализацию метода draw()
в базовом классе Shape
?
Конечно, нет. Shape
является общим, это не означает только «круг» или «прямоугольник» или «треугольник». Нет способа обеспечить разумную реализацию для Shape::draw()
потому что мы даже не знаем, какую форму он представляет.
Можно ли предоставить пустую реализацию для Shape::draw()
?
Видимо это так. Однако, если подумать, ясно, что это небезопасно. Объекты класса, который расширяется Shape
и не обеспечивает собственную реализацию метода draw()
не может быть нарисовано.
Потому что класс Shape
не может обеспечить достойную реализацию метода shape
, он должен как-то сигнализировать об этом производным классам и заставлять их предоставлять реализацию.
То, как это сигнализирует об этой ситуации, является abstract
ключевое слово. abstract
Метод сообщает читателям класса, что класс не может предоставить реализацию, потому что он слишком универсален и делегирует эту ответственность каждому классу, который его расширяет.
Класс, который имеет abstract
метод не полностью определен. Это причина, почему это abstract
класс, и он не может быть создан.