@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?

Что нужно изменить или какой паттерн можно применить в данном случае?
  • Вопрос задан
  • 202 просмотра
Пригласить эксперта
Ответы на вопрос 4
@HVVI
Нормально. Инициализация родителя через вызов его конструктора - хорошая практика, в том числе потому что вы не забудете передать ему значения.
Ответ написан
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);


Угадай какой конструктор будет вызван ?
Ответ написан
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;
}
Ответ написан
SilenceOfWinter
@SilenceOfWinter
та еще зажигалка...
А в TestimonialWidget то это зачем?
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
Zelo Москва
от 130 000 руб.
Digital Clouds Новосибирск
от 60 000 руб.
АКМЭ сервис Санкт-Петербург
от 100 000 руб.