Задать вопрос
rammtw
@rammtw
Press CTRL+S to save project

Как вынести похожие сущности в один абстрактный класс?

Имеется сервис рассылки смс-сообщений. При отправке сообщений через его API, указывается параметр provider (с какого провайдера будут отправляться сообщения), как вы понимаете у каждого провайдера имеется свое API, методы соответственного у всех называются по разному (например где-то /send/sms,, где-то /sendsms или /send и т.д., /balance или /getbalance и т.д.)
Для каждого провайдера есть отдельный класс, с его методами, так вот вопрос, как сделать, что-то типа единого класса с методами (sendSms(), getBalance() и т.д.) через который будет выбираться класс провайдера. Надеюсь понятно написал :)
  • Вопрос задан
  • 278 просмотров
Подписаться 2 Оценить Комментировать
Решения вопроса 1
@Arik
Быстрый вариант
class Sms
{
    protected static $instances = [];

    public static function getInstance($id = 'default')
    {
        $map = [
            'first' => 'FirstSmsHandler',
            'second' => 'SecondSmsHandler',

            'default' => 'FirstSmsHandler',
        ];

        if (!isset(self::$instances[$id])) {
            if (!isset($map[$id])) {
                throw new \Exception(sprintf('Unknown hadler `%s`', $id));
            }

            $handler = new $map[$id];

            self::$instances[$id] = new self($handler);
        }

        return self::$instances[$id];
    }

    protected $handler;

    public function __construct(SmsHandler $handler)
    {
        $this->setHandler($handler)
    }

    public function setHandler(SmsHandler $handler)
    {
        return $this->handler = $handler;
    }

    public function changeHandlerByName($handlerName)
    {
        $map = [
            'first' => 'FirstSmsHandler',
            'second' => 'SecondSmsHandler',

            'default' => 'FirstSmsHandler',
        ];

        if (!isset($map[$handlerName])) {
            throw new \Exception(sprintf('Unknown handler `%s`', $handlerName));
        }

        $handler = new $map[$handlerName];

        $this->setHandler($handler);

        return $this;
    }

    public function __call($name, $arguments)
    {
        return call_user_func_array([$this->handler, $name], $arguments);
    }
}

$sms = new Sms(new FirstSmsHandler());
$sms->changeHandlerByName($_POST['provider']);

$sms = Sms::getInstance($_POST['provider']);

$sms->getBalance();


Можно еще почитать как ларавел реализовывает контракты, сервис контайнеры и сервис провайдеры. Там через конфиг просто меняем контейнер и уже работаем с другим классом. Почитайте.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@khrisanfov
Программист
Нужно создать интерфейс с методами sendSms() и getBalance(), затем реализовать его для каждого провайдера. Количество классов будет соответствовать количеству провайдеров, у всех будет один общий интерфейс.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы