0

我目前正在尝试找到一个“确定的”解决方案(意思是:找到一个看起来有效的解决方案,并符合 OOP 规则)解决我一段时间以来反复出现的问题:我的不同部分的共享数据问题代码。

请注意,我在这里的任何地方都没有使用任何 MVC 框架。我只是将我的数据类称为模型,将显示类称为视图(因为它的专有名称与 MVC 模式无关,人们在 MVC 模式“创建”之前就制作了视图和模型)。

这是我的问题:每当我制作一个使用一些相当扩展数据的应用程序(例如游戏)时,我都会尝试分离逻辑(运动、碰撞等)并在两个类中显示。但是后来,我偶然发现了一个问题:如何将存储在我的逻辑类中的数据与我的视图类中的相应显示对象“绑定”,而不在不同类之间复制数据、引用或其他东西?

让我们举一个基本的例子:

  • 我有一个 MyLogicClass,持有一个“EntityData”对象的向量(每个对象都有位置、大小、各种状态、处理我的项目逻辑的所有内容)

  • 我有一个 MyViewClass,为 MyLogicClass 中的每个 EntityData 创建和显示 Sprite,并在游戏循环中更新它们后使它们移动。

我首先想到的是在每个数据元素中存储其对应的视图,从而允许我循环遍历我的 Vector 以更新项目逻辑,然后相应地更新视图。但这迫使我在 MyViewClass 中保存一个 MyLogicClass 引用,以确保我可以定位实体数据,迫使我将这两个类结合起来(我不想做的事情)。

另一方面,在我的数据模型(MyLogicClass 的 EntityData 对象具有 ID 参数)和我的 View 类(Sprites 持有对其原始实体数据 ID 的引用)中,每个实体都有一个 ID 的解决方案。但是,当我想针对一个特定实体强制我在我的数据模型中循环它时,然后再次循环它以在我的视图中找到相关的 Sprite。这个解决方案允许我在我的数据和我的视图之间有松散的耦合,但是每帧循环通过数百个元素两次(可能发生!)对于我来说确实听起来没有优化性能。

我可能对整个问题给予了应有的重视,但我已经不止一次偶然发现了这一点,而且我很想对此有一些其他的看法。

你们对这样的问题有什么建议/解决方案吗?

对于这种情况,是否还有其他一些我可能不知道的数据格式/层次结构?

4

2 回答 2

1

我所做的是使用事件和事件侦听器将它们“链接”在一起。我有我的“模型部件”抛出“显示部件”捕获和渲染/更新的特定事件。

我发现这确实让我可以通过编写测试代码来构建我的一些测试,这些代码将侦听某些事件并以这种方式进行错误检查。我的代码仍然是独立的并且可以单独测试:我可以通过触发并确保抛出具有正确值的正确事件来测试我的“模型”。同样,我可以编写一些测试代码来抛出可以被“显示”捕获的预设事件,看看它是否有任何问题。

然后,一旦一切正常,我只需重用那些相同的事件侦听器并链接到“彼此”。

后来我的“控制器”(用户输入)将操纵“模型”部分,这将导致事件被抛出到“显示器”,从而被渲染/更新。

我不知道这在遵循 mvc 模式方面是否“正确”,我对这类事情也没有任何正式的知识。我也会对其他人更有见识的意见感兴趣。

于 2012-11-17T10:24:00.493 回答
0

我想也许你想多了这个问题。我有时会这样做。

您的视图类显然必须具有某种类型的模型链接,而事件是实现此目的的好方法。这里有一些简单的东西给你一个想法。

 // Model class
 package
 {
    class MyModel extends EventDispatcher
    {
        // you can make them public but that would 
        // be against some oop practices. so private it is
        private var m_position:Vector2D; 

        MyModel(){}

        // one way of doing getters/getters
        // example: theModel.SetPosition(something);
        public function GetPosition():Vector2D { return m_position; }
        public function SetPosition(value:Vector2D):void 
        { 
            m_position = value; 
            ModelChanged();
        }

        // the other way
        // sample: theModel.position = something;
        public function get position():Vector2D {return m_position; }
        public function set position(value:Vector2D):void 
        { 
            m_position = value; 
            ModelChanged();
        }

        private function ModelChanged():void
        {
            dispatchEvent(new Event(Event.CHANGE));
        }
    }
}


// now for our view.
package
{
    class MyView extends Sprite // or whatever
    {
        private var model:MyModel;

        MyView(model:MyModel)
        {
            this.model = model;

            model.addEventListener(Event.CHANGE, handleModelChanged);

            // fire off an event to set the initial position.
            handleModelChanged(NULL);
        }

        private function handleModelChanged(evt:Event):void
        {
            x = model.position.x;
            y = model.position.y;
            // etc etc etc.
        }
    }
}

无论如何,如果您要在模型文件中拥有逻辑,那么显然您不需要设置器,如果模型之外没有任何东西需要更改它,那么设置器没有理由。但是你确实需要吸气剂。

这将模型与视图分离,您可以以任何方式编写任何视图,并且您所提供的只是模型更改时的处理程序。只需使用 getter 公开您的视图所需的任何数据。

您现在只需遍历模型,如果其中一个发生更改,它将触发一个事件,并且正在侦听的视图将更新。

希望我没有错过任何东西,这解释了你想要什么。

编辑:我忘了补充,如果你使用类似更新功能的东西,你不必到处都有“ModelChanged()”。只需更新,并在您完成活动时触发。

于 2012-11-17T19:15:03.617 回答