@vellmur

ООП — нормальная ли это практика вызывать родительский конструктор каждый раз при создании потомка?

Я пытаюсь спроектировать базу для создания сервиса по работе с виджетами. Все виджеты зависят от обьекта Client и шаблонизатора TemplateService.

Выделив общие свойства и методы получилась такая структура:

Родительский класс Widget:

abstract class Widget
{
    protected $client;
    protected $templateService;
    protected $template;

    public function __construct(TemplateService $templateService, Client $client) 
    {
        $this->templateService = $templateService;
        $this->client = $client;
    }

    public function setTemplate(string $template)
    {
        if (!file_exists($template)) {
            throw new \Exception('Widget template "' . $template . '" was not found.');
        }

        $this->template = $template;

        return $this;
    }

    abstract protected function renderWidget() : string;
}


Пример потомка ContactWidget:

class ContactWidget extends Widget implements ICustomerForm
{
    use CustomerFormTrait;

    private $formFactory;

    public function __construct(TemplateService $templateService, $client, FormFactoryInterface $form)
    {
        parent::__construct($templateService, $client);

        $this->formFactory = $form;
    }

    public function renderWidget() : string
    {
        $form = $this->buildForm();

        return $this->templateService->render($this->template, [
            'form' => $form->createView(),
            'token' => $this->client->getToken()
        ]);
    }

    public function buildForm() : FormInterface
    {
        $form = $this->formFactory->create(ContactType::class, $this->customer);

        return $form;
    }
}


Пример потомка TestimonialWidget:

class TestimonialWidget extends Widget
{
    public function __construct(TemplateService $templateService, Client $client)
    {
        parent::__construct($templateService, $client);
    }

    public function renderWidget() : string
    {
        $testimonials = $this->client->getTestimonials();

        return $this->templateService->render($this->template, [
            'testimonials' => $testimonials
        ]);
    }
}


Все работает, но решение кажется не очень красивым. Придерживаясь этой структуры придется каждый раз вызывать родительский конструктор. Мне кажется существует решение поизящнее и хочется изначально заложить правильную структуру. Отказаться от конструктора в родительском классе или в классе потомка? Передавать зависимости через set/get?

Что нужно изменить или какой паттерн можно применить в данном случае?
  • Вопрос задан
  • 215 просмотров
Решения вопроса 1
Adamos
@Adamos
Без реального использования этих классов говорить не о чем. Может быть, логичнее будет такой родитель:
abstract class Widget
{
    protected $template;

    public function __construct() 
    {   }

    public function setTemplate(string $template)
    {
        if (!file_exists($template)) {
            throw new \Exception('Widget template "' . $template . '" was not found.');
        }

        $this->template = $template;

        return $this;
    }

    abstract public function render(TemplateService $templateService, Client $client) : string;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
leha_gorbunov
@leha_gorbunov
Программист
Ну так и убери из TestimonialWidget конструктор если он только родителя вызывает.

class TestimonialWidget extends Widget
{
   public function renderWidget() : string
    {
        $testimonials = [[
            'name' => 'John Snow',
            'text' => 'Test'
        ]];

        return $this->templateService->render($this->template, [
            'testimonials' => $testimonials
        ]);
    }
}


Потом вызови
$widget = new TestimonialWidget($templateService, $client);


Угадай какой конструктор будет вызван ?
Ответ написан
Ваш ответ на вопрос

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

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