也许不是最准确的标题,但是有点难以描述。也许你们可以在这里帮助我吗?我正在使用MVC格式编写游戏,并且我希望每个基类(控制器,模型和视图)都对其附带功能进行引用,从而形成某种三角形(即,模型对控制器进行引用)定义它,以及引用它的视图,等等。)这些类中的许多看起来像这样:
public class Model {
public Controller controller;
public View view;
public void Connect (Controller controller, View view) {
this.controller = controller;
this.view = view;
}
}
没关系,但是每当我打算拉起ChildModel的控制器时,都需要转换为适当的ChildController以获得正确的版本。我可以使一个实用程序方法/获取程序来获取适当的转换项目,但我不想为每个子类重写这段代码。我以为可以通过使基类成为通用类来解决此问题,但是现在我遇到了一个问题,其中新的通用类需要引用试图定义它们的类,因此:
public class Model<V, C> where V : View<?, C> where C : Controller<?, V> {
public Controller<?, V> controller;
public View<?, C> view;
public void Connect (Controller<?, V> controller, View<?, C> view) {
this.controller = controller;
this.view = view;
}
}
如您所见,这在基类中很快变得混乱。我不知道要在试图定义约束的模型中放置什么符号(参考上面的示例)。将“模型”放入问号似乎也无法编译,因为我遇到了一个地狱般的拳击转换问题。
有没有办法实现我所追求的目标,或者我只是想在这里变得太聪明?如果这行得通,我希望能够声明类型限制为“三角形”的子类,这样就可以避免不必要的强制转换或辅助方法:
public class ChildModel<ChildView, ChildController> {
public ChildModel () {
this.controller <- calls ChildController type, not base type!
}
}
有人有想法么?
最佳答案
您似乎在混淆所有权与交互。所有权意味着一个人拥有另一个,而交互作用则意味着它们如何相互交流。 MVC主要定义了三个参与者之间的交互,尽管您可以说视图和控制器都拥有模型。
在所示的代码中,一个类拥有一个属性,因此控制器类拥有一个视图,而一个视图拥有一个控制器。
var model = new Model();
var view = new View<Controller<Model, View<Controller, Model>, ...
这不适用于您想要的泛型,因为交互成为循环。这是鸡与蛋的问题:鸡来自于由鸡产下的鸡蛋。我们可以通过赋予视图的控制器所有权以及模型的控制器和视图所有权来解决大多数问题。
public class Model
{
}
public interface IView<M>
{
M Model { get; }
}
public class MyView : IView<Model>
{
public MyView(Model model)
{
Model = model;
}
public Model Model
{
get;
}
}
public interface IController<V, M>
{
M Model { get; }
V View { get; }
}
public class MyController : IController<MyView, Model>
{
public MyController(MyView view, Model model)
{
View = view;
Model = model;
}
public Model Model
{
get;
}
public MyView View
{
get;
}
}
我们仍然使用泛型来执行此操作,到目前为止,您可以轻松访问大多数信息,而无需引入循环引用。
class Program
{
public static void Main()
{
var model = new Model();
var view = new MyView(model);
var controller = new MyController(view, model);
}
}
现在,如果要确保视图具有对控制器的引用,则可以通过属性来执行此操作。
view.Controller = controller;
您可以不理会我刚刚给您看的所有内容,然后选择资产注入路线。这意味着您可以简单地做到这一点,而不是通过构造函数创建对对象创建方式的循环引用限制的依赖关系。
var model = new Model();
var view = new View();
var controller = new Controller();
model.View = view;
model.Controller = controller;
view.Controller = controller;
view.Model = model;
controller.View = view;
controller.Model = model;
无论使用哪种方法,诀窍都是避免当前代码中出现循环依赖问题。大多数MVC框架提供了丰富的数据绑定,这打破了类之间的直接耦合,但是如果您没有这样做,则必须编写某些内容或查找某些内容,或者在语言规则的限制范围内工作。
有很多方法可以解决此问题。在我撰写本文时,还发布了另一个答案,因此您也应该注意一下。