Mvc with multiple window designs

I am working on an application and I am using the MVC pattern. My current plan is to create an MVC template for each window. For example, my login window has its own mvc system. Another window where they make a choice has their own mvc system. Then mainview has its own mvc system ...

It just seems a little silly. I was wondering if this is normal so that each window has its own mvc? If not, how could I do it better?

The problem I am facing is how can I get the mvc log window to properly open the selection window, and then after they make their selection, how does the selection window bring up the main window?

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

+4
source share
3 answers

How can I correctly call this selection window from the login window?

Use the observer pattern . If any view changes the state of the model, all registered listeners will be notified, and everyone can update themselves to reflect the change. This example refers to three general ways of implementing an observer pattern.

+3
source

Despite its simplicity, the MVC pattern is incomprehensible many times. First you need to understand what needs to be held in all these separated components and how they can talk together.

  • View: any user interface element. A good reusable viewing element should be used anywhere. Therefore, the view does not know the context and does not support the specific controller with which it will interact. What is known to opinion is its own state and one (or many) common listener, which it is called when some action occurs. The presentation element knows what it is declaring, conveying changes, but should not change its state on its own. Example: the button will broadcast the “click” action, and you will specify the name of the button through the controller using a method like aButton.setLabel("click me!");

  • Model: a model is capable of processing the state of a data set; it usually implements some functions for saving and loading its state to / from a file. A model is a box that really should not change its state unless someone (the controller) asks for it. Again, a good model does not know about the view or even the controller. The way it is. A very simple model is, for example, String. You can load a string from a file, save it to a file, change it to uppercase, substring, and so on. The string has a state, does not know about this context, and just waits for someone to use it. If the model knows the controller that you cheated, the model will not be reused unless you implement the same controller (which is bad practice even when using interfaces).

  • Controller: the controller is actually your program, this is the part in which the decision is made. Where is it? well ... your main function already a controller. Again, all decisions are made in the controller. When someone clicks on the button, the method inside the controller is called (and not one of them), when you want to update the label, you do it from the controller. Also, all threads must be processed in controllers. Does your model upload a large file? Create a thread in the controller, ask the model to load the image, and then notify the main thread about it (off topic, find the event loop)

Several windows, here we are!

View / Controller, how do they interact with each other? Responsibility for viewing is only to ensure controller events (the text field has been changed, a button is pressed, etc.) and be able to display the way we want. For example window.setTitle ("myWindow"); We may be tempted to place material in a view that should be in the controller and vice versa.

For example, if you create a warning panel, you will have two buttons (ok, cancel) and one label for the text. Does the view know what to do as soon as you click "ok" on "cancel"? of course not ... but once clicked the panel, which should disappear by itself. Conversely, if you create a panel for entering a password, View will not be able to hold the verification process. This will be the controller’s task to agree or not provide the password provided.

Well, I think you understand all of MVC, now it's time to talk about the proper way to communicate all these components:

How should the dispatcher be notified? Actually, it depends on the language you use. First think about the following:

  • Avoid viewing to know the controller.
  • The view should not display information from the controller and not call methods for it. How does the controller say something happened? Through observers (or listeners).

A small bracket: a view can refer to the methods of another view if it is simply a question of the correctness of its visualization. For example, resizing a window ensures that all components (subviews) of these windows are displayed correctly, but the controller cannot be notified that the window has resized.

The connection between MVC is the key! So how does it work?

  • Who will create and display the view? Controller!

  • Who must register to view events? Controller too ... after creating

  • How? The task of viewing is to transmit events when they occur. Usually, through ActionListener in java, observers in objective-c, C ++ lambda functions, access functions in javascript. And the controller specified in it implements the correct actionPerformed "callback" actionPerformed in java, a selector, or even the callback function itself, if you provided a callback function for the presentation.

  • Therefore, when the view created from the controller fires the event, the controller is notified and it will have to process this event. If the controller wants to change something in the view, it is quite simple, because the controller always owns and knows the view.

  • For each window, the controller: this sounds good, you do not have to have only one controller (no model, no representation ...) when creating an instance of the login controller object, which you could create and display the login window as well.

  • One instance of the model for the service. Here is an example of a singleton design pattern, you probably only need one “authentication model” because you are either logged in or logged in in one application. Therefore, instead of creating multiple instances of the input model for each window, it depends on the input state, you really want to have only one. You can do this through a static instance of the entry model object. This is called singleton.

Now, how to ensure that what we change into the model is replicated to all controllers? A simple case is one controller and one model. The controller changes the model and waits until the model is changed, then to use the change (for example, to display it in the form). What happens if a model is passed through multiple controllers? For example, a model is a login service, you have 2 states: login and logout. 2 use this model, each of these controllers has its own view (window), one only shows the password field, and the second is a window with an image that is displayed only if the user is logged in. not one solution for this case, but several. One uses a listen / watch pattern. Several controllers can listen to model changes. As soon as one of them changes it, all controllers will be notified of the change and, therefore, will update the view. Another way is to save the notification center (this is another template) and allow either the controller or the model to broadcast what happened, all the controllers interested in this event will be notified of the change and processing of the event. The latter solution is especially interesting for cases when the model can change at any time (of course, through a controller hidden somewhere). The notification center uses event loops and most of the time it tries to notify about the main event loop (which should be your stream of user interface controllers).

So, for our example, if the login process is disabled, I would use a simple listener. 2 controllers listen for model changes. One controller, after entering the password, will call the login.loginWithPassword(String some password) method model; if the password is ok, the model will broadcast the "loginStateChanged" event. All listeners (including our 2 controllers) will receive this event and report that the view is updated with what we want (for example, display an image that can only be displayed during registration).

In the above example, our controller requested the model, and the model directly triggered an event, this is in the controller thread, which is a great reason for the lack of access risk concurrency (same thread = no problem) however:

If the login was remote, for example, authentication of an online service, we will knock on the server door and wait for a response. Since this process may take several seconds, the controller will wait for the server to respond. To avoid this, we must send the request to another thread and simply change the view with the message (waiting for the server) until we get a response from the server. As soon as we receive a response (or after a timeout if there is no answer), the stream that we created earlier will receive a model response that is true or false. A very bad idea is to update the view directly to the result. The problem is that the thread that received the response does not work in the main controller thread, so if we update the view, we will encounter concurrency access (if the view object changes to 2 threads exactly the same when you encounter a crash). One way to ensure that we don’t mess with the main thread is to simply send the model response to the main thread through a notification that will be sent in the main event loop. In this case, I would use the notification center instead of just broadcasting from the model. It is interesting to note that some frames provide broadcasting in the cycle of the main event. There is even a better solution using block or lambda functions, but it comes out of this question.

Summarizing:

  • Neither the view nor the model should know the controller
  • Only the controller knows both of them.
  • Pay attention to how they talk to each other, use listeners or a notification if there are more than 1 controller for one model.
  • The process is always performed as follows:
    • The controller creates a view and listens to it.
    • The view indicates that an action has occurred.
    • The action process controller may ask the model to change something.
    • The model gives the result (either returning the function through the listener, or a callback)
    • The controller processes the result.
    • The controller updates the view with the result.
+3
source

In fact, I believe that what I'm going to do is use a mediation template to control the interaction between these views. So the connection is very limited, and she gets the exact job that I wanted. Let me know what you think.

+1
source

All Articles