Jump to content

MVC where view configuration depends on model state


Recommended Posts

OK, I will pose an OOP design patterns question and see if anyone wants to discuss this:

I spent some time last night studying the MVC compound pattern in ch. 12 of Head First Design Patterns. My implementation of the pattern without knowing exactly what I was doing isn’t too far from what the book describes (although I missed some key ideas that I plan to implement next time) but the relatively simple example in the book leaves me wondering about a couple things. The most important is:

In the book example the controller determines when the view’s components are grayed out or activated based on user events. The view does respond to changes in the model but only to update values, not to activate or deactivate view components. (In other words, the view is just a simple data listener.) Often in a real control application, however, like the one I am doing--and most of us using LabVIEW do, the view components should be grayed out or activated based at least in part on the state of the model, not just user events in the view. For instance, in an application that controls a motion axis the user might press an initialize button on the view but the move to position button should only be active once when the axis initialization completes (a change in the model’s state). In my solution I created a separate controller (a UI controller) that acts on state information from the controller. Probably the two controllers could be combined. (I am actually using three controllers, though, because I have two models--one for a moving axis and another for an acquisition device, but that is probably not necessary either.) Who knows how this “should be” done?

Link to comment

I guess an alternative I am describing is really a version of the Mediator pattern (which I guess sometimes is seen as a variation of MVC):

See Fig. 4 here: http://java.sun.com/developer/technicalArticles/javase/mvc/

and Fig. 4-5 here: http://developer.apple.com/documentation/C..._section_4.html

(Also see Head First Design Patterns pp. 559 and 622-3 for a discussion of the mediator pattern.)

I'm trying to figure out which is the best solution....

Link to comment

Well I think you are on the right track. I wouldn't get hung up on that book that says the graying out should only be a response to user events. In a real-world I/O application, you are often using gray-out to display the availability of the model's functionality. If the model notifies you that some ability is currently unavailble, then it's obvious that the user interface should respond by disabling any inputs which invoke the ability. Graying stuff out is part of the way that you display your model state.

It seems like the main reason to use the mediator pattern is to make your interface 'skinnable'. By funnelling all interaction through the mediator, and requiring that no application logic is in the UI view, it frees you up to make different programs to view the data and all use the same API (the mediator) for consistency and reuse. I think most LabVIEW applications don't need to be skinned, and writing the extra API and supporting code could be classified as 'a waste of time'. (contrary opinions are welcome!)

That being said, I think that processing as little logic as possible in the View is a great idea. Too often I have found it difficult to change my code because some functionality was partly implemented in both my view and my model, but I think you are already hip to that problem, otherwise you wouldn't be writing this post.

Link to comment

Thanks very much, Jim and jdunham, for your helpful responses.

OK, I drew a diagram to indicate what I did do. I like it in some ways but not in others.... I was kind of hoping learning the MVC pattern properly would shine a beacon on the enlightened way....

A couple notes:

The signals in my solution are shared variables.

I think my solution is similar to the Mediator pattern solution in some respects but I have divided the work into several controllers rather than one.

Note that I have two models. I actually think this is a good idea....

The advantages I see:

Each element/controller combination is completely independent of the other element/controllers in the subsystem and is swappable (e.g., we can use an alternate view). [The classic MVC pattern neatly swaps the view/controller pairs (they are a matched set) using the Strategy pattern.]

Each element/controller combination can run on a separate machine.

Disadvantages:

I have this set up so that the subsystem starts each element, then runs each controller, then shuts down each element. This is OK but perhaps not as neat yet as in the classic MVC pattern, where the controller is constructed with the model and the controller creates the view, so that starting and stopping them together is a little simpler. Maybe I can come up with something similar for my implementation. Right now none of the elements knows the others exist. I will likely have to add in checks where needed at some point.

Also, there are three controllers instead of one. [Counterpoint to these: I created a simple classic MVC in LabVIEW for a trivial test application just fine. I had to use VI Server to do the equivalent of Java's "createView" so that the view/UI would be nonblocking. This worked fine for the simple application. In my real application I would have to use VI Server also to run the input signal model as well if I wanted to incorporate it into the same controller, and this is a bit troubling and difficult in LabVIEW currently especially if one wants to initialize the class (to set input channels, for example) first. It doesn't seem to me that we should handle the two model parts in the same controller, but I may simply be wrong about this. Comments?]

It is not exactly clear to me where the best place is to put the signal creation (I am creating shared variable libraries at runtime.)

It is not clear that even in a SCADA system any of a subsystem's parts need to run on a separate machine. (Remote panels can work to export the view anyway.)

More a technology disadvantage than a model disadvantage:

Using networked shared variables or a similar publish subscribe system means that even if all the subsystem components are on the same computer they rely on the local network to communicate. (I think this is true but I haven't checked this.)

I looked at the Fowler-described patterns and am still evaluating them--it takes a while for this stuff to sink in my brain!

I am wondering what the best search term to find a "motion control design pattern" (or similar pattern) is. (I tried that but haven't found much helpful yet.... I expect there is a commonly applied pattern for this somewhere....)

Paul

Link to comment

I reread some topics and thought about this more last night and I think I am getting my definition of controller confused. The main difference between the simple MVC test project I created and the actual project is that the commanded device is more complex in the actual project. It has multiple states, etc. In fact, what I had labeled model controllers use a similar structure to what I used in what I was calling the view controller, but these are not the "controller" of the MVC compound pattern. They are really part of the model itself. Actually, the whole lower part of the diagram is really part of the model. So I'm really not as far from the classic MVC as I thought.

This is good because now it makes sense to use the strategy pattern to select the controller and the creation of the model, controller, and view have a logical place in the MVC model. (The model passes itself to the controller and the controller instantiates the view.) This seems all very good!

I still decided to have the model communicate with the view indirectly (cf. the Cocoa or Passive View models already cited)--which was the topic of the post--for a few reasons.

1) It doesn't seem to be too much of a departure from the classic MVC model.

2) The ways I can think of to make the view change its appearance as a whole when a value updates don't make sense from the standpoint of a view. (These include writing logic in the view, writing logic in each view component, or triggering a value change event when an indicator updates programmatically--the last of which fortunately does not happen in LabVIEW.)

3) OK, and I haven't yet tested binding indicators across platforms, but that isn't likely to be a serious issue. (It should be possible with DataSocket.)

Thanks, all!

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.