Мне нужно создать архитектуру MVC, где классы View и Controller уже были написаны в виде шаблонов следующим образом:
template<class Model, class View>
class Controller { /* Implement Controller */ };
template<class Model, class Controller>
class View { /* Implement View */ };
У меня также есть модельный класс:
class Model { /* Implement Model */ };
Я не контролирую, как создаются классы Model, View и Controller. Теперь, как мне создать экземпляр контроллера или представления?
Чтобы лучше объяснить ситуацию, если я хочу создать Controller с использованием классов View и Model выше (мне НЕ разрешено использовать какие-либо другие классы), я получаю:
ПРИМЕЧАНИЕ: неверный код C ++ следует
Controller< Model, View< Model, // ad infinitum
тогда как следующее также недействительно:
ПРИМЕЧАНИЕ: неверный код C ++ следует
Controller< Model, View< Model, Controller > > c;
Это возможная реализация
template<typename View, typename Model>
struct Controller {
View *view;
Model *model;
Controller() : view(0), model(0) {}
void setUp(View *v, Model *m) {
view = v;
model = m;
}
virtual void change() = 0;
};
template<typename Controller, typename Model>
struct View {
Controller *controller;
Model *model;
View() : controller(0), model(0) {}
void setUp(Controller *c, Model *m) {
controller = &c;
model = &m;
}
virtual void display() = 0;
};
Для создания экземпляра трюк заключается в извлечении класса из шаблона, в котором в качестве параметра указан объявленный класс:
struct MyModel {
int x;
MyModel(int x) : x(x) {}
};
struct MyController;
struct MyView : View<MyController, MyModel>
{
void display() { std::cout << model->x << std::endl; }
};
struct MyController : Controller<MyView, MyModel>
{
void change() { model->x = 44; }
};
После этого вы можете создавать экземпляры и настраивать их
int main(int argc, const char *argv[]) {
MyModel m(42);
MyView v;
MyController c;
v.setUp(&c, &m); c.setUp(&v, &m);
v.display();
c.change();
v.display();
return 0;
}
Это компилирует:
class MyView;
class MyController: public Controller<Model,MyView>{};
class MyView: public View<Model,MyController>{};
MyController myC;
MyView myV;
Но это зависит от того, как написаны Controller и / или View. MyView является неполным на момент получения MyController, поэтому можно использовать только указатели.
Ты не сможешь это сделать. Несколько мыслей, чтобы вы пошли:
Используйте шаблоны только для определенных функций-членов
Если вашим классам не нужно хранить элементы данных, вы можете написать:
template<class Model>
class Controller {
public:
void foo() // does not need View
{ ... }
template<typename View>
void bar(const View& v) // works with a specific View
{ ... }
};
возможно Controller
не нужно знать View
?
template<class Model> // no dependency on View
class Controller { /* Implement Controller */ };
template<class Model, class Controller>
class View { /* Implement View */ };
// no it works
Controller<MyModel> ctrl;
View<MyModel, Controller<MyModel>> view;
Используйте интерфейс:
class IController { ... };
class IView { ... };
template<class Model>
class Controller : public IController { /* Implement Controller */ };
template<class Model>
class View : public IView { /* Implement View */ };
Получите типы из ваших типов шаблонов:
class MyView;
class MyController : public Controller<MyModel,MyView> { };
class MyView : public View<MyModel,MyController> { };
Здесь вы должны иметь в виду эту проблему: Два шаблонных класса состоят из членов друг друга