Задать вопрос
myks92
@myks92
Нашёл решение — пометь вопрос ответом!

Yii Как избежать дублирование методов в классах?

Всем привет! Есть вопрос связанный с дублированием методов в классах.

Есть несколько классов, допустим их название:
— Profile
— Price
— Post

В них есть одинаковые константы и одинаковые методы:

//Статусы
   const STATUS_NOT_PAID = 0;
    const STATUS_PAID = 1;
    const STATUS_CANCEL = 3;


и сами методы:
/**
     * Статистический метод получения списка статусов
     * @return array
     */
    public static function getStatusList()
    {
        return [
            self::STATUS_NOT_PAID => 'Не оплачено',
            self::STATUS_PAID => 'Оплачено',
            self::STATUS_CANCEL => 'Отменена'
        ];
    }

    /**
     * Получение статуса из модели
     * @return mixed
     */
    public function getStatusName()
    {
       ArrayHelper::getValue(self::getStatusList(),$this->status);
    }


Данные методы и константы дублируются из одного класса в другой. При этом если что-то измениться в статусах придется везде изменять, где они применены.

Как в данном случае лучше реализовать одинаковые методы без дублирования и удобного использования в разных классах?

Наследовать от одного класса нельзя, так как классы разные. Интерфейсы помогут только не допустить ошибок, но не помогут от избавления дублирования из класса в класс. Я предполагаю, что нужно использовать ‭в поведениях и прикреплять где нужно.... Правильно ли я думаю?
  • Вопрос задан
  • 200 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 3
DieZz
@DieZz
Как мне видится - самый логичный вариант сделать отдельный класс, который будет возвращать имя статуса. Это может быть хелпер, компонент и все что угодно, в зависимости от специфики вашей бизнес логики. Например
interface HasStatus
{
    public const STATUS_NOT_PAID = 0;
    public const STATUS_PAID     = 1;
    public const STATUS_CANCEL   = 3;

    public function getStatus(): int;
}

class StatusHelper
{
    /**
     * Статистический метод получения списка статусов
     *
     * @return array
     */
    public static function getStatusList()
    {
        return [
            HasStatus::STATUS_NOT_PAID => 'Не оплачено',
            HasStatus::STATUS_PAID     => 'Оплачено',
            HasStatus::STATUS_CANCEL   => 'Отменена',
        ];
    }

    public function getStatusName(HasStatus $entity): string
    {
        ArrayHelper::getValue(self::getStatusList(), $entity->getStatus());
    }
}

Соответственно все ваши модельки должны имплементирвать интерфейс HasStatus. Таким образом вся бизнес логика находится в одном месте и отвязана от БД
Ответ написан
kimono
@kimono
Web developer
Можно ещё через interface + trait:
interface StatusListable
{
    public function getStatusName(): string;
}

trait StatusReturner
{
    public static function getStatusDescriptions()
    {
        return [
            self::STATUS_NOT_PAID => 'Не оплачено',
            self::STATUS_PAID => 'Оплачено',
            self::STATUS_CANCEL => 'Отменена',
        ];
    }

    public function getStatusName($status): string
    {
        return ArrayHelper::getValue(self::getStatusDescriptions(), $status);
    }
}
Ответ написан
@kttotto
пофиг на чем писать
Если через наследование от общего класса не хотите, то можно этот общий класс передавать как параметр, например через конструктор. Т.е. вынесите эти общие методы и константы в один класс , а затем при создании своих объектов, передайте через конструктор экземпляр этого общего класса.

Второй вариант, этот общий класс инкапсулировать в Ваши Profile, Price, Post, т.е. сделать его экземпляром одного из полей в них.

Ну и третий вариант, если не хотите передавать его и как параметр и не хотите инкапсулировать, то сделайте из него хелпер, т.е. сам общий класс и его методы сделайте статическими, тогда в своих Profile, Price, Post будете обращаться к методам и полям хелпера напрямую.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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