mvc多窗口设计

发布于 2024-12-09 05:53:51 字数 290 浏览 1 评论 0原文

我正在开发一个应用程序,并且正在使用 MVC 模式。目前我的计划是为每个出现的窗口提供一个 MVC 模式。例如,我的登录窗口有自己的 mvc 系统。他们进行选择的另一个窗口有自己的 mvc 系统。然后 mainview 有自己的 mvc 系统......

这看起来有点愚蠢。我想知道这是否正常,让每个窗口都有自己的 mvc?如果没有的话,我怎样才能更好地安排呢?

我遇到的麻烦是,如何让登录窗口 mvc 正确调用选择窗口,然后在他们做出选择后,选择窗口如何调用主视图窗口?

感谢您的帮助!如果您需要更多信息,请告诉我。

I am working on an application and i am using the MVC pattern. Currently my plan is to have an MVC pattern for each window that comes up. For instance, my login window has its own mvc system. Another window where they make a selection has its own mvc system. Then the mainview has its own mvc system...

This just seems a little goofy. I was wondering if that was normal, to have every window have its own mvc? If not, how could i arrange this better?

The trouble i am running into is, how do i get the log in window mvc to correctly call the selection window and then after they make their selection, how does the selection window call the mainview window?

Thanks for any help! If you need more info, please let me know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云淡风轻 2024-12-16 05:53:51

尽管 MVC 模式很简单,但很多时候人们并不理解它。首先,您需要了解所有这些独立组件中应该包含什么以及它们如何一起通信。

  • 视图:任何 UI 元素。一个好的可重用视图元素应该可以在任何地方重用。因此,视图不知道它的上下文,也不知道他将与之交互的特定控制器。视图所知道的是它自己的状态和一个(或多个)通用侦听器,一旦发生某些操作,它将调用该侦听器。视图元素知道它的状态,广播更改,但不应自行更改其状态。 :按钮将广播“单击”操作,您将通过控制器通过类似 aButton.setLabel("click me!");

    的方法设置按钮名称

  • 模型设置按钮名称:模型能够处理数据集的状态,它通常会实现一些函数,以便将其状态保存到文件中或从文件中加载其状态。模型是一个盒子,除非有人(控制器)要求,否则实际上不应该改变其状态。同样,一个好的模型不知道视图甚至控制器。事情就是这样。一个非常简单的模型是例如字符串。您可以从文件加载字符串、将其保存到文件、将其更改为大写、子字符串等。字符串确实有状态,不知道它的上下文,只是等待有人使用它。如果模型知道你被愚弄的控制器,则模型将无法重用,除非你实现相同的控制器(即使使用接口,这也是一个不好的做法)。

  • 控制器:控制器实际上是你的程序,这是做出决策的部分。它在哪里?好吧……你的main function已经是控制器了。同样,所有的决定都由控制器做出。当有人单击按钮时,会调用控制器中的方法(而不是视图方法),当您想要更新标签时,您可以从控制器中执行此操作。此外,所有线程都应该处理到控制器中。您的模型正在加载一个大文件?在控制器中创建一个线程,要求模型加载图像,然后在完成后通知主线程(脱离主题,搜索事件循环)

多个窗口,我们在这里!

视图/控制器如何相互交互?
视图的职责只是向控制器提供事件(文本字段更改、按钮被单击等)并能够按照我们想要的方式显示。例如 window.setTitle("myWindow");我们可能会试图将应该放入控制器的内容放入视图中,反之亦然。

例如,如果您正在构建一个警报面板,您将有 2 个按钮(确定、取消)和一个文本标签。单击“确定”或“取消”后,视图知道要做什么吗?当然不是……但是一旦单击该面板将不得不自行消失。相反,如果您确实创建了一个用于输入密码的面板,则视图将无法保留验证过程。控制者的工作就是同意或不同意所提供的密码。

好吧,我想您已经了解了所有 MVC,现在是时候讨论让所有这些组件一起对话的正确方法了:

视图应该如何通知控制器?实际上这取决于您使用的语言。首先想到以下几点:

  • 避免通过视图来了解控制器。
  • 视图不应该从控制器获取信息,也不应该调用它的方法。它如何告诉控制器发生了什么事?通过观察者(或听众)

小括号:如果只是为了保持视觉正确,一个视图可以调用另一个视图的方法。例如,调整窗口大小将确保该窗口的所有组件(子视图)仍然正确显示,但控制器可能不会收到窗口更改其大小的通知。

MVC之间的通信是关键!那么,它是如何工作的呢?

  • 谁将创建并显示视图?控制器!

  • 谁应该注册才能观看活动?控制器也是......创建后

  • 如何?视图的工作是在事件发生时广播事件。通常通过 java 中的 ActionListener、objective-c 中的观察者、c++ 中的 lambda 函数、javascript 中的函数回调。并且列出的控制器在 java 中实现了正确的“回调”函数 actionPerformed、选择器,甚至直接回调函数(如果您向视图提供了函数回调)。

  • 因此,当从控制器创建的视图触发事件时,控制器会收到通知并且必须处理该事件。如果控制器想要更改视图中的某些内容,这很容易,因为控制器始终拥有并知道视图。

  • 每个窗口都有一个控制器:听起来不错,在创建登录控制器对象实例时,您不必只有一个控制器(既不是模型也不是视图……),也可以创建并显示登录窗口。

  • 每个服务一个模型实例。这里出现了单例设计模式,您可能只需要一种“身份验证模型”,因为您要么在同一个应用程序中登录,要么注销。因此,您实际上只想拥有一个,而不是根据登录状态为每个窗口创建多个登录模型实例。您可以通过登录模型对象的静态实例来完成此操作。这称为单例。

现在如何确保我们更改为模型的内容将复制到所有控制器?简单的情况是一个控制器和一个模型。控制器正在更改模型并等待模型更改,然后使用更改(例如将其显示到视图中)。如果模型通过多个控制器共享会发生什么?例如,该模型是一个登录服务,您有2种状态:登录和注销。
2 个控制器正在使用此模型,每个控制器都有自己的视图(窗口),一个仅显示密码字段,第二个是一个带有图像的窗口,仅在用户登录时才显示。有对于这种情况,不是只有一种解决方案,而是有多种解决方案。一种是使用倾听/观察模式。多个控制器可以监听模型的变化。一旦其中之一发生更改,所有控制器都将收到更改通知,因此将更新视图。另一种方法是保留一个通知中心(这是另一种模式)并让控制器或模型广播发生的事情,然后所有对此事件感兴趣的控制器将收到更改通知并处理该事件。对于模型可以随时更改的情况(当然通过隐藏在某处的控制器),最后一个解决方案特别有趣。通知中心正在使用事件循环,并在大部分时间尝试通知主事件循环(这应该是您的 UI 控制器的线程),

因此对于我们的示例,如果登录过程处于脱机状态,我将使用一个简单的侦听器。 2 个控制器正在监听模型变化。输入密码后的一个控制器将调用该方法的模型 login.loginWithPassword(String some password) 如果密码正确,该模型将广播一个事件“loginStateChanged”。然后,所有侦听器(包括我们的 2 个控制器)都将获取此事件,并告诉视图以我们想要的任何内容进行更新(例如显示仅在登录时才能显示的图像)。

在上面的示例中,我们的控制器询问模型,模型直接触发事件,这是在控制器的线程内,这很好,因为不存在并发访问的风险(同一线程=没有问题),但是

:如果是远程的,比如在线服务认证,我们会去敲服务器的门,等待它的答复。由于此过程可能需要几秒钟,控制器将一直卡在等待服务器的答复。为了避免这种情况,我们应该将请求发送到另一个线程,然后用消息修改视图(等待服务器),直到我们从服务器得到答案。一旦我们得到答案(或者在超时后,如果没有答案),我们之前创建的线程将得到模型的答案是真还是假。直接用结果更新视图是一个非常糟糕的主意。问题是得到答案的线程没有运行到主控制器的线程中,因此如果我们更新视图,我们确实会面临并发访问(如果视图对象在您的同时被两个线程更改)遇到崩溃)。确保我们不会干扰主线程的一种方法是通过将在主事件循环中分派的通知将模型的答案发送到主线程。在这种情况下,我尤其会使用通知中心,而不是模型的简单广播。有趣的是,一些框架在主事件循环中提供广播。使用块或 lambda 函数有更好的解决方案,但它超出了这个问题的范围。

总结一下:

  • 视图和模型都不应该知道控制器
  • 只有控制器知道它们两者
  • 注意它们彼此交谈的方式,如果同一模型有超过 1 个控制器,请使用侦听器或通知。
  • 该过程始终如下:
    • 控制器创建视图并监听它
    • 视图告诉控制器发生了一个操作
    • 控制器处理操作可能会要求模型更改某些内容
    • 模型给出结果(通过侦听器或回调返回函数)
    • 控制器处理结果
    • 控制器用结果更新视图。

Despite its simplicity the MVC pattern is many time not understood. At first you need to understand what should be held into all of those separated components and how they might talk together.

  • The View : Any UI element. A good reusable view element should be reused anywhere. Therefore the view does not know it's context nor the specific controller he will be interacting with. What the view is aware is it's own state and one (or many) generic listener which it will call once some action happen. A view element knows it state, broadcast changes but should not change its state by itself. Example: A button will broadcast an action "clicked", and you will set the button name through a controller through a method like aButton.setLabel("click me!");

  • The model : A model is able to handle a state of a dataset, it usually implements some functions in order to save and load its state into / from a file. A model is a box which should actually not change its state unless someone (a controller) asks for it. Again, a good model is not aware of the view or even the controller. It is just the way it is. A very simple model is for example a String. You can load the string from a file, save it to a file, change it to uppercase, substring and so on. A string does have a state, is unaware of it's context and just wait for someone to use it. If the model knows the controller you are fooled, the model will not be reusable unless you implement the same controller (which is a bad practice even using interfaces).

  • The controller : The controller is actually your program, this is the part where the decision part is made. Where it is ? well… your main function is already the controller. Again, all the decisions are made into a controller. When someone clicks on a button, a method within a controller is invoked (and not a view one), when you want to update a label, you do it from the controller. Also all the threads should be handled into controllers. Your model is loading a large file ? Create a thread into the controller, ask the model to load the image, then notify the main thread once done (out of topic, search for event loop)

Multiple windows, here we are!

View / Controller how do they interact to each other ?
The responsibility of the view is only to provide to a controller events (text field changed, a button was clicked and so on) and to be able to be displayed the way we want. For example window.setTitle("myWindow"); We can be tempted to put stuff in the view that should be into the controller and conversely.

For example, if you are building an alert panel you will have 2 buttons (ok, cancel) and one label for the text. Do the view knows what to do once you click "ok" of "cancel" ? certainly not… but once clicked the panel will have to disappear by itself. Conversely, if you do create a panel for entering a password, the View will not be able to hold the validation process. This will be the controller's job to agree or not on the provided password.

Okay I guess you understood all the MVC, now it's time to talk about the right way to let all those components talk together:

How should the view be notifying the controller ? Actually it depends on the language you are using. At very first think of the following:

  • Avoid the view to know the controller.
  • The view should not be fetching information from the controller, nor invoking methods to it. How it will tell the controller something happened ? Through observers (or listeners)

Little parenthesis: A view can invoke methods of another view if it is just a matter of keeping it visually correct. For example resizing a window will ensure all the components (subviews) of this windows are still displayed correctly, but the controller might not be notified the window changed its size.

Communication between the MVC is the key! So, how does it work ?

  • Who will create and display a view ? The controller!

  • Who should be registering to view events ? The controller too… after creating

  • How ? The view's job is to broadcast events when they happen. Typically through ActionListener in java, observers in objective-c, lambda functions c++, function callback in javascript. And the controller to listed to it implementing the right "callback" function actionPerformed in java, a selector, or even directly the callback function if you provided a function callback to the view.

  • So when a view created from the controller is firing an event, the controller is notified and will have to handle this event. If the controller wants to change something into the view, it's quite easy cause the controller always own and knows the view.

  • To each window a controller : it sounds good, you are not obliged to have only one controller (neither one model or view…) while creating a login controller object instance, that one could create and display a login window as well.

  • One instance of model per service. Here comes the singleton design pattern, you will probably need only one "authentication model" because you are either logged in or logged out within the same application. So instead of creating several login model instance for each window dependent on the login state, you actually want to have only one. You can do this through a static instance of the login model object. This is called a singleton.

Now how to ensure that what we are changing into a model will be replicated to all the controllers ? The simple case is one controller and one model. The controller is changing the model and waits the model to be changed to then use the change (for example to display it into a view). What happen if the model is shared through several controllers ? For example, the model is a login service, you have 2 states : logged in and logged out.
2 controllers are using this model, each of those controller do have it's own view (window), one is just displaying a password field and the second one is a window with an image which is displayed only if the user is logged in. There is not one solution to this case but several. One is using the listening / observing pattern. Several controllers can be listening for the model's changes. Once one of those is changing it, all the controllers will be notified by the change and therefore will update the view. Another way is to keep a notification center (it's another pattern) and to let either the controller or the model to broadcast what happened, all the controllers interested in this event will then be notified by the change and process the event. This last solution is especially interesting for cases where the model can change at anytime (of course through a controller hidden somewhere). The notification center is using event loops and tries most of the time to notify into the main event loop (which should be your UI controllers's thread)

So for our example, if the login process is offline I would be using a simple listener. The 2 controllers are listening to the model changes. One controller after entering the password will call the method's model login.loginWithPassword(String some password) if the password is fine, the model will broadcast an event "loginStateChanged". All the listeners (including our 2 controllers) will then get this event and tell the view to get updated with whatever we want (for example display the image which can be shown only while logged).

In the example above, our controller was asking the model and the model directly fire the event, this within the thread of the controller, which is fine cause there is no risk of concurrency access (same thread = no problem) however:

If the login was a remote one, for example an online service authentication,we would be knocking at the server's door and wait for its answer. As this process might take some seconds the controller would keep stuck waiting for the server's answer. To avoid this case we should then send the request into another thread and just modify the view with a message (waiting for server) until we get the answer from the server. Once we get the answer (or after the timeout if no answer) the thread we created before will get the model's answer being true or false. A very bad idea is to update the view directly with the result. The problem is the thread who got the answer, is not running into the main controller's thread, and therefore if we do update the view, we do face a concurrency access (if the view object is changed by 2 threads exactly in the same time you encounter a crash). One way of insuring we are not messing with the main thread, is simply to send the model's answer to the main thread through a notification which will be dispatched in the main event loop. In this case especially I would be using a notification center instead of a simple broadcast from the model. It is interesting to note that some framework are providing broadcast within the main event loop. There is even better solution using block or lambda functions but it is but out of this question's scope.

To summarise:

  • Neither the view nor the model should know the controller
  • Only the controller do know both of them
  • Pay attention to the way they are talking to each other, use listeners or notification if there is more than 1 controller for the same model.
  • The process is always as follow:
    • The controller create the view and listen it
    • The view tells the controller an action happened
    • The controller process the action might ask the model to change something
    • The model gives a result (either returning the function, through a listener or callback)
    • The controller process the result
    • The controller update the view with the result.
守护在此方 2024-12-16 05:53:51

如何从登录窗口正确调用该选择窗口?

使用观察者模式。如果任何视图更改了模型的状态,则所有注册的侦听器都将收到通知,并且每个侦听器都可以更新自身以反映更改。这个示例提到了实现观察者模式的三种常见方法。

How do I call that selection window from the login window correctly?

Use the observer pattern. If any view changes the model's state, then all registered listeners will be notified, and each can update itself to reflect the change. This example mentions three common ways to implement the observer pattern.

紫竹語嫣☆ 2024-12-16 05:53:51

实际上我相信我要做的是使用调解器模式来控制这些视图之间的交互。这样,耦合就非常有限,并且它可以完成我想要的确切工作。让我知道你的想法。

Actually i believe that what i am going to do is use a Mediator pattern to control the interaction between these views. This way the coupling is very limited and it gets the exact job done that i was wanting. Let me know what you think.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文