Как избежать этого дополнения к нашему божественному объекту

Наше веб-приложение позволяет пользователям загружать файлы. В нашем веб-приложении есть два объекта бога:

  • Пользовательский объект (3000+ строк)
  • Файловый объект (более 3000 строк)

Общее использование на данный момент:

$file = File::getByID($_GET['file_id']);
$user = User::getByID($file->ownerID);

echo $file->title;
echo $user->name;

В настоящее время мы обсуждаем добавление объекта пользователя в объект файла в качестве другой общедоступной переменной. Поскольку везде, где мы используем файловый объект, нам нужен связанный пользовательский объект.

Так что использование будет:

$file = File::getByID($_GET['file_id']);

echo $file->title;
echo $file->user->name;

Мы пытаемся реорганизовать эти объекты бога, и добавление пользовательского объекта к объекту файла кажется, что мы усугубляем проблему. Однако у меня нет веских аргументов, чтобы не согласиться с предлагаемым изменением.

Было бы здорово получить некоторую помощь по следующим вопросам:

  1. Является ли добавление пользовательского объекта в файловый объект плохой идеей?
  2. Если это плохая идея, каков главный аргумент, чтобы не делать этого?
  3. Как еще я могу провести рефакторинг этих объектов?

Заметки

  • Я знаю, что количество строк не является верным показателем, но другие наши классы имеют 50-150 строк и используются редко.
  • Я сократил общее использование до важных битов, поэтому извиняюсь за отсутствие лучших практик.
  • Я уже пытаюсь удалить статические методы и публичные переменные из нашего кода.

1 ответ

Решение

Я бы определенно добавил User объект как свойство File класс, так как это фактическое представление модели данных за ним. Это также придаст коду большую ясность и даст более краткий код использования File объект. Это также будет означать File Класс не должен выполнять никакой проверки на достоверность, если установлен идентификатор владельца: если объект передан, он может предположить, что он действителен (или он не должен был быть в состоянии построить).

class File
{
    protected $owner;

    /**
     * @var User $owner mandatory
     */
    public function __construct(User $owner)
    {
        $this->setOwner($owner);
    }

    public function setOwner(User $owner)
    {
        return $this->owner;
    }

    public function getOwner()
    {
        return $this->owner;
    }
}

Теперь ясно, что File имеет обязательное свойство owner, который является User,

Я также рекомендовал бы использовать средства доступа вместо общедоступных свойств. Это будет более надежно в будущем, например, оно также позволит вам лениво загрузить пользователя, если вы захотите сделать это позже.

class File
{
    protected $ownerId;
    protected $owner;

    public function getOwner()
    {
        if (!$this->owner && $this->ownerId) {
            $this->owner = User::getById($this->ownerId);
        }
        return $this->owner;
    }
}

Это подразумевает, что ваш слой данных соответствующим образом заполняет объект, а также потребует адаптированного конструктора с потерей автоматической проверки типа (только конструктор все еще имеет проверку типа в установщике):

/**
 * @var $owner int|User the user object or it's ID
 */
public function __construct($owner)
{
    if (is_object($owner)) $this->setOwner($owner);
    else $this->ownerId = $owner;
}

Что касается вопроса, где ваша статика User::getById() должен идти: вы должны разделить операции с данными (извлечение и сохранение объектов) в отдельном слое.

class UserStore
{
    public function getById($id)
    {
        // code to retrieve data from where ever, probably database
        // or maybe check if the user was already instantiated and registered somewhere...
        $user = new User($data['name'], $data['email']/*, ....*/);
        return $user;
    }
}

Для этого последнего я бы не советовал создавать свою собственную библиотеку ( называемую ORM), существует множество отличных реализаций. Взгляните на Doctrine ORM.

Наконец, я бы сказал, что уменьшение размера класса не должно быть самоцелью. однако вы можете уменьшить его сложность, извлекая логику, которая не присуща самому объекту, как в случае со свойством owner. Другим примером может быть путь к файлу: может быть, путь хранится относительно, и у вас есть функции, чтобы преобразовать его в абсолютный путь или получить расширение или имя файла. Эта функциональность может быть извлечена в отдельном FileMeta класс или как вы хотите позвонить, может быть, даже File класс в другом пространстве имен: FileSystem\File,

Другие вопросы по тегам