Рефакторинг кода. Как оптимизировать количество if?
Есть код, который принимает json данные и в зависимости от типа выполнить определённые действия. Весь код обработки находится в if'ах, добавление новых типов оказалось неудобным. Сейчас планирую вынести обработку в отдельные сервисы под каждый тип, а информацию передавать с помощью DTO. Но, это все равно не избавляет от сложности и количество if. Рассматривал возможность заменить на switch/match, но, такой вариант кажется не совсем верным. С похожей проблемой столкнулся и в другой части кода, где нужно обрабатывать по-разному в зависимости от состояния.
if ('text' === $message->getType()) {
// code
}
if ('poll' === $message->getType()) {
// code
}
if ('image' === $message->getType()) {
// code
}
С ООП немного знаком в теории, на практике, осмысленно, применять получается редко. Насколько я знаю в решении проблемы должен помочь полиморфизм, но, как правильно его применить не пойму.
Ответы (1 шт):
Это похоже на Стратегию. Но как я полагаю в вашем случае там всё равно придётся для него if'ы
Но для облегчения решения проблемы я бы предложил сделать мапу. Наглядно:
Выделяем интерфейс для классов с логикой:
interface StrategyInterface { public function execute(array $data): void; }тут входные и выходные данные те, что вам нужны. Например входных параметров может не быть. Или может что-то возвращать. Это понятно.
Делаем разные классы, которые имплементируют интерфейс
class TextHandler implemets StrategyInterface { public function execute(array $data): void { DB::user->save($data); } } class PollHandler implemets StrategyInterface { public function execute(array $data): void { $implodedData = implode(', ', $data); $stringWithoutUnderscore = str_replace('_', '', $implodedData); file_put_contents('file.txt', $stringWithoutUnderscore ); } } class ImageHandler implemets StrategyInterface { public function execute(array $data): void { header("Content-Type: image/png"); $im = imagecreate($data['width'], $data['height']); or die("Невозможно создать поток изображения"); $background_color = imagecolorallocate($im, 0, 0, 0); $text_color = imagecolorallocate($im, $data['r'], $data['g'], $data['b']); imagestring($im, 1, 5, 5, "A Simple Text String", $text_color); imagepng($im); imagedestroy($im); } }Далее делается какой-то менеджер с хранилищем ссылок:
class HandlersManager { const HANDLER_TEXT = 'text'; const HANDLER_POLL = 'poll'; const HANDLER_IMAGE = 'image'; public static function handlersMap(): array { return [ HANDLER_TEXT => TextHandler::class, HANDLER_POLL => PollHandler::class, HANDLER_IMAGE => ImageHandler::class, ]; } }Константы скорее всего можно определить в каждом классе в виде свойства и брать вместо
HANDLER_TEXTчто-то типаTextHandler::getName()который будет возвращать значение, в свойстве$name. Базовый методgetNameможно написать в каком-то базовом классе для всех тех хэндлеров.Далее мы например получаем
$_GETзапрос с каким-то параметром. Например в$_GET['handler_type']будет необходимое значение. Получается:$handlersMap = HandlersManager::handlersMap(); $handler = new $handlersMap($_GET['handler_type']); $handler->execute($_GET['handler_data']);
P.S. Можно создать базовый класс и передавать data в конструктор, а у обработчика просто вызывать ->execute();