Помогите понять паттерн Model-View-Controller, как он выглядит в голом С++, а то в интернетах всё про php да java\C#
Как я его понимаю:
Допустим есть GUI который показывает данные и в котором есть кнопки\поля ввода чтобы данные менять.
Также есть какой-то код который делает какую-то полезную работу — использует эти данные и как-то реагирует на их изменение.
Допустим у нас есть один объект данных — класс Model
struct IModelReader
{
virtual A get_dataA() = 0;
virtual B get_dataB() = 0;
};
struct IModelWriter
{
virtual void set_dataA(A value) = 0;
virtual void set_dataB(B value) = 0;
};
struct IModel : IModelReader, IModelWriter
{
virtual void load() = 0;
virtual void save() = 0;
};
class Model : public IModel
{
public:
Model();
... тривиальная реализация get/set методов
};
и один объект GUI, у него будет класс UserInterface,
struct IView
{
virtual void updateAll() = 0;
};
class UserInterface : IView
{
public:
UserInterface(IModelReader& model, IController& controller);
virtual void updateAll()
{
outputForA.text = model.get_dataA().toString();
outputForB.text = model.get_dataB().toString();
}
private:
void onUserRequestChangeDataA(A newValue)
{
controller->setDataA(newValue);
}
void userWantReloadData() { controller->loadData(); }
void userWantCloseMe() { controller->saveData(); }
void seemsThatUserGoneAway() { controller->log("WARNING: user doesn't work"); }
...
}
и контроллер:
struct IController
{
virtual void setDataA(A newValue) = 0;
virtual void loadData() = 0;
virtual void saveData() = 0;
virtual void log(string s) = 0;
}
class Controller : public IController
{
public:
Controller(IModel& model, IView& view, ILog& log = ILog::getNullLogger());
virtual void setDataA(A newValue)
{
A oldA = model.get_dataA();
if(newValue == oldA)
return;
model.set_dataA(newValue);
view.updateAll();
log.log("A changed");
}
virtual void loadData()
{
model.load();
view.updateAll();
}
virtual void saveData()
{
model.save();
}
}
запускаем...
int main()
{
struct Holder
{
Holder() : m(), v(m, c), c(m, v) {}
Model m;
UserInterface v;
Controller c;
}
holder;
holder.v.run();
}
а кто же собственно будет делать полезную работу?
Controller и так перегружен методами.
Значит надо делать еще один класс, например Worker, который тоже должен читать\писать данные, и знать об их изменении.
Для уведомления об изменении есть IView::updateAll(), значит можно написать
struct ComplexView : IView
{
virtual void updateAll() { for each(IView* v in views) v->updateAll(); }
list<IView*> views;
};
Впрочем у Worker'а всеравно будут методы которых нет у GUI и наоборот, так что и UserInterface, и Worker надо передавать Controller'у
class Worker : IView
{
void beginCalculateValueOfA(function<void(A)> handler) { ... }
};
void Controller::updateA()
{
worker.beginCalculateValueOfA([this](A a){ model.set_dataA(a); allViews.updateAll(); });
}
так как оно, MVC, на самом деле выглядит?