Описание проблемы
У меня есть класс модели, который выглядит примерно так (чрезвычайно упрощен, некоторые элементы и многие, многие методы опущены для ясности):
class MyModelItem
{
public:
enum ItemState
{
State1,
State2
};
QString text() const;
ItemState state() const;
private:
QString _text;
ItemState _state;
}
Это основной элемент приложения и используется во многих разных частях кода:
- Сериализован/десериализован в/из различных форматов файлов
- Его можно записать в базу данных или прочитать из нее
- Он может быть обновлен с помощью "импорта", который считывает файл и применяет изменения к текущей загруженной модели в памяти.
- Он может быть обновлен пользователем через различные функции графического интерфейса.
Проблема в том, что этот класс вырос за эти годы и теперь имеет несколько тысяч строк кода; это стало ярким примером того, как нарушить принцип Одиночной ответственности.
Он имеет методы для установки "текст", "состояние" и т.д. непосредственно (после десериализации) и один и тот же набор методов для их установки из пользовательского интерфейса, который имеет побочные эффекты, такие как обновление "lastChangedDate" и "lastChangedDate", lastChangedUser и т.д. Некоторые методы или группы методов существуют даже более двух раз, причем каждый из них делает в основном одно и то же, но немного отличается.
При разработке новых частей приложения вы, вероятно, используете неправильные пять различных способов манипулирования MyModelItem
, что делает его чрезвычайно трудоемким и расстраивающим.
Требования
Учитывая этот исторически сложившийся и чрезмерно сложный класс, цель состоит в том, чтобы разделить все различные проблемы его на разные классы, оставив в нем только основные элементы данных.
В идеале я бы предпочел решение, в котором объект MyModelItem
имеет ничего, кроме const
для доступа к данным, а модификации могут быть сделаны только с помощью специальных классов.
Каждый из этих специальных классов мог бы затем содержать фактическую конкретную реализацию бизнес-логики (сеттер "текста" мог бы сделать что-то вроде "если текст, который будет установлен, начинается с определенной подстроки, а состояние равно" State1 ", установите его в" State2").
Первая часть решения
Для загрузки и хранения всей модели, состоящей из многих объектов MyModelItem
и некоторых других, шаблон посетителя выглядит многообещающим решением. Я мог бы реализовать несколько классов посетителей для разных форматов файлов или схем баз данных и иметь метод save
и load
в MyModelItem
, который принимает каждый объект-посетитель каждый.
Открытый вопрос
Когда пользователь вводит определенный текст, я хочу проверить его. Та же проверка должна быть сделана, если вход поступает из другой части приложения, что означает, что я не могу перенести проверку в пользовательский интерфейс (в любом случае проверка только на основе UI часто является плохой идеей). Но если проверка выполняется в самом MyModelItem
, у меня снова есть две проблемы:
- Разделение проблем, с которых была начата цель, отрицается. Весь код бизнес-логики по-прежнему "сбрасывается" в плохую модель.
- При вызове другими частями приложения эта проверка должна выглядеть по-другому. Реализация различных методов проверки-настройки - это то, как это делается прямо сейчас, у которого плохой запах кода.
Теперь ясно, что валидация должна быть перемещена за пределы UI и модели, в какой-то контроллер (в смысле MVC) или в набор классов. Затем они должны украсить/посетить/etc фактический немой модельный класс с его данными.
Какой шаблон проектирования программного обеспечения лучше всего подходит для описанного случая, чтобы разрешить различные способы изменения экземпляров моего класса?
Я спрашиваю, потому что ни один из шаблонов, которые я знаю, полностью решает мою проблему, и я чувствую, что здесь что-то не хватает...
Большое спасибо за ваши идеи!