Страницы

Поиск по вопросам

среда, 18 декабря 2019 г.

Для чего нужны абстрактные классы и интерфейсы PHP?

#php #классы


Пример из жизни если можно =)

Вроде писать классы можно и без них

Где их можно применить?

Вот нашел развернутый ответ

ссылка на ответ

Объясните на примере по ссылке почему нельзя вместо абстрактного класса использовать
обычный класс, например не реализовывая какие то функции ы нем а реализовывая в потомках
Ведь по сути обычный класс ничем не отличается от абстрактного, зачем тогда он нужен
(абстрактный)?
    


Ответы

Ответ 1



Можно, конечно, и без абстрактных классов. Но с ними все же удобнее. Например в следующем случае: вам надо реализовать иерархию классов, где есть один базовый класс и несколько производных. При этом нужно реализовать некий метод, который должен быть у всех классов, но во всех он должен быть реализован по-своему. Реализовать этот метод в базовом не абстрактном классе вы не можете - в таком случае он будет общим для всех производных. Можно, конечно, сделать его виртуальным в базовом классе и переопределять в производных, но тогда напрашивается вопрос: зачем этот метод реализовывать в базовом классе, если нужны только его реализации, зависящие от конкретного производного класса. Это иллюстрируется хрестоматийным примером про геометрические фигуры, когда у вас есть базовый класс Figure и производные от него Circle, Square, каждый из которых должен иметь метод для отрисовки (скажем, Draw()). Тут можно увидеть, что во-первых, Draw() должен быть разным для каждого из производных классов, а во-вторых, его не очень-то и нужно реализовывать в базовом, так как непонятно, как должна выглядеть "просто фигура". При этом у класса Figure может быть какой-то набор базовых методов, реализация которых может быть общей для всех производных. То есть вполне разумно сделать базовый класс именно абстрактным (а не интерфейсом или обычным, не абстрактным классом)

Ответ 2



Судя по ответам, могу сказать, что люди все же не до конца понимают случаи использования абстрактного класса. В ответах выше можно задать вопрос: разве я не могу использовать для этих целей интерфейс или обычный класс? Создать методы без реализации и распространить их на группу классов ? Для этого есть интерфейс. Создать общий класс от которого наследовать логику ? Без проблем, для этого можно использовать обычный класс. Представьте, что вам нужно описать модель работы бензозаправки. Для ее отработки вам безусловно понадобится экземпляр автомобиля. Но в данный момент вы не хотите задумываться о конкретной реализации этого класса - его методы могут возвращать mock значения. К тому же вам наверняка могут понадобится свойства в этом классе и соответственно рабочие геттеры и сеттеры. К тому же, стоит проконтроллировать, что соседние разработчики не будут дописывать к этому классу какую-то конкретную логику, чтобы потом использовать ее в своем коде и таким образом связать ваш код лишними зависимостями. Для этих целей идеально подойдет именно абстрактный класс, созданием которого вы говорите: "это класс с очень общей логикой и возможностью хранить данные в свойствах. В последствии мы сделаем для него конкретных потомков, но сейчас не до этого. Пожалуйста, не дописывайте сюда методов с конкретной логикой."

Ответ 3



Если совсем грубо, то можно сказать, что абстрактный класс - это этакий интерфейс, но в котором вы можете для части методов написать реализацию и, в последствии, унаследовать ее. Реальный пример. Была у меня задача, в рамках которой надо было общаться с тремя разными типами БД (mysql, oracle, informix). Причем логика довольно запутанная была, в одном скрипте приходилось лазить туда, потом сюда, потом обратно и все это по нескольку раз. Соответственно разумным решением было сделать под каждую БД свой синглтон, оберткой над PDO, плюс пара утилитарных методов для удобства формирования запросов. Теперь следим за руками. Фактически все эти три класса коннектора отличались только строкой коннекта и выставлением специфического окружения для каждой из баз (только для Informix на самом деле, но не суть). Вот тут то нам на помощь приходит абстрактный класс, в котором мы реализуем всю общую логику и делаем два абстрактных метода getConnectionString() и setEnvironment(). В итоге все три класса просто наследуют один этот абстрактный и каждый из них реализует только по два этих метода, вместо всей простыни. Чем такой подход лучше простого наследования? Тем, что вы физически не сможете накосячить и не реализовать в дочерних классах необходимые методы.

Ответ 4



Абстрактный класс. Как минимум в классе есть один абстрактный метод. Общий смысл в том что определяя функцию в базовом классе(абстрактном), мы заранее говорим, что этот метод в потомках пригодится (точно пригодится!) и в базовом классе только определяем этот метод, а в потомках его описываем что зачем(обязательно!) Можно использовать, чтобы не забыть реализовать какой-нибудь метод.)

Ответ 5



Реальный пример: Вы делаете сайт (CMS), вывод модулей в браузер. Вы не знаете какие модули будут выводиться и кто их будет делать: новости, форум, календарь, блог, ссылки, фотографии... Вы не знаете как модуль будет генерировать HTML, имя класса модуля и как в нем что реализовано. Не знаете и это не ваша проблема и забота. Вам нужно только "заставить" чтобы все модули подчинялись одному методу: ПОКАЖИСЬ ( назовем его show). Для этого создаете абстрактный класс с этим методом. Затем создаете любые модули основываясь на абстрактном классе. В итоге вывод модулей выглядит примерно так: foreach($modules as $module) { $module->show(); // тут каждый модуль сам генерирует и отображает свой html код } С помощью базового абстрактного класса вы привели все модули к одной функции вывода show() в HTML. Не зная ничего про модуль вы точно знаете что у него есть метод который вам нужен Конечно без этого можно обойтись, но с опытом понимаешь что так лучше...

Ответ 6



Абстрактные классы нужны для того, что бы вынести похожую логику для нескольких одинаковых классов в отдельный файл. Пример: у меня несколько видов депозитов, логика расчётов для всех депозитов вобщем-то одинаковая (её разместил в абстрактном классе), но однажды ко мне прибежит менеджер и скажет, что проценты по одному определённому депозиту необходимо считать от количества шагов пройденных человеком, а так как я могу перегрузить методы в классах наследниках, то в определённых депозитах я легко смогу написать другую логику и не затронуть друге депозиты.. Интерфейсы необходимы для того что бы объявить одинаковые методы для классов наследников. пример: у меня на сайте есть несколько платёжных систем, и в будущем я намерен подключить ещё пару, и вот для всех этих систем неплохо бы разработать единый интерфейс, что бы я мог просто создать нужную мне платёжную систему и пользоваться ей как обычно в любом другом месте (привет фабричный метод), конечно я мог бы для разных платёжных систем просто создать одноимённые методы, но это не правильно и рано или поздно это приведёт к ошибке, поэтому лучше объявить интерфейс. Так же есть её трейты. для того что бы вынести некоторые методы общие для классов, читай множественное наследование. И вообще все эти штуки очень хорошо ложатся на unit тесты

Комментариев нет:

Отправить комментарий