Supervising Controller - Martin's "GUI Architectures" series (2)

zz from www.martinfowler.com

To be translated...

Supervising Controller

Factor the UI into a view and controller where the view handles simple mapping to the underlying model and the the controller handles input response and complex view logic.

[TBD: Not sure yet whether to use the word 'controller' or 'presenter' here.]

Many UI frameworks provide the ability to easily map between the view and model, often using some kind of Data Binding. These approaches are very effective in allowing you to declaratively set up a relationship between elements in the view and model. Usually, however, there are more complex relationships which require you to have more complex view logic. This logic can be hard to manage, and in particular hard to test, while embedded in the view.

Supervising Controller uses a controller both to handle input response but also to manipulate the view to handle more complex view logic. It leaves simple view behavior to the declarative system, intervening only when effects are needed that are beyond what can be achieved declaratively.

How it Works

Supervising Controller decomposes presentation functionality into two parts: a controller (often called presenter) and view. The domain data that needs to be displayed is separate, and following rough MVC terminology I'll refer to it as a model, although it need not be a Domain Model. The basic division of responsibilities echoes the Model-View-Presenter architecture in its Dolphin form, as described by Bower and McGlashan.

A Supervising Controller has two primary responsibilities: input response and partial view/model synchronization.

For input response the controller operates in the presenter style. The user gestures are handled initially by the screen widgets, however all they do in response is to hand these events off to the presenter, which handles all further logic.

For view/model synchronization the controller defers as much of this as reasonable to the view. The view typically uses some form of Data Binding to populate much of the information for its fields. Where Data Binding isn't up to more complex interactions then the controller steps in.

Figure 1

Figure 1: Class diagram for the assessment example.

Figure 2

Figure 2: Sequence diagram showing the response for putting in a low actual value.

In the assessment window, the initial text change is handled by the text field widget in the view. This widget is observed by the controller, so when the text changes the widgets emits an event which results in the controller's actualFieldChanged method being called. This method then handles the full response to the event. It first updates the reading model object's actual value. The window observes the reading object so the change to the reading's value triggers a refresh. It's pretty easy to map the actual and variance text fields' text to the appropriate properties of the reading, so that updates those values. For the purposes of our example changing the color is a bit more involved. The reading object can, and should, determine which category the reading should fit into. A sophisticated widget might be able to bind its text color to a category like this, but we'll assume we don't have such a clever young thing. In this case controller takes over setting the variance field's text color directly.

As the example shows, the essence of a good Supervising Controller is to do as little as possible. Let the view handle as much as possible and only step in when there's more complex logic involved.

One of the prime reasons to use Supervising Controller is for testability. Assuming the view is hard to test, by moving any complex logic into the controller, we put the logic in a place that's easier to test. In order to run tests on the controller, however, we do need some form of view, so a Test Double is often in order. With the double in place, we don't have any need for UI framework objects in order to test the more awkward parts of the UI behavior.

This testability issue affects another decision - whether the controller should access the view and its widgets directly, or through an intermediary. With an intermediary we build a Gateway for the the controller. The gateway defines an interface for the controller to manipulate. One implementation then adapts the window's interface while the other provides a stub for testing (you could also use a mock). This is the same approach that you need for Passive View.

Figure 3

Figure 3: Using an intermediary between the controller and the window.

The discussion so far suggests using Flow Synchronization with Supervising Controller, but this need not be the case. It is possible to use Observer Synchronization, but it needs to be modified so that it's the controllers that observe the model rather than the views.

When to use it

There are two main reasons to look into using a Supervising Controller: to separate out the complexity of an Autonomous View, and to improve testability.

The separation advantage is that it pulls all the behavioral complexity away from the basic window itself, making it easier to understand. This advantage is offset by the fact that the controller is still closely coupled to its screen, needing a pretty intimate knowledge of the details of the screen. In which case there is a real question mark over whether it's worth the effort of making it a separate object.

The testability reason is the more compelling one. Many people I've talked to have found using some form of controller has made a big difference to making a UI that is properly testable.

If testability is your driver then the driving issue is how much behavior to leave in the view. Passive View is a very similar pattern to Supervising Controller, but with the difference that Passive View puts all the view update behavior in the controller, including simple cases. This results in extra programming, but does mean that all the presentation behavior is testable. The choice between the two depends on what kind of Data Binding support you have and whether you're happy to leave that untested by controller tests.

A third alternative is Presentation Model. This again pulls most behavior away from the view, but leaves it to the view to synchronize all its updates. There isn't a great deal of the difference in test coverage between Presentation Model and Supervising Controller - much of the choice (as with Passive View) depends on personal judgments.

Significant Revisions

19 Jun 06: First publication in development area of website.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用python实现: 【问题描述】 英文电影中参演人员名单一般以某种方式进行排版显示。给定一个未排版的文件listin.txt,该文件中每行参演人员名单由冒号":"分隔成前后两部分,但格式杂乱无章,单词(由除空格和水平制表符之外的其它字符构成)之间可能有多个空格或水平制表符分隔。编写程序,要求将其按如下排版规则排版输出到另一个文件listout.txt中: 1.从标准输入读取一整数,作为排版后所有各行冒号":"在一行中的固定位置;假设输入的整数肯定大于排版后所有各行冒号":"前的字符个数,位置从1开始计数; 2.冒号":"左边的单词串以行头为基准左对齐,左边的最后一个单词与冒号之间以空格填充;冒号":"右边的单词串以冒号":"为基准左对齐,最后一个单词后只有回车换行符,不再有其它字符; 3.冒号":"左右两边的单词间都只有一个空格分隔,并且要求冒号两边至少各有一个空格。 假设输入文件中每行字符个数不超过100。 【输入形式】 待排版的参演人员名单从当前目录下的listin.txt文件中读入;表示冒号":"位置的整数从标准输入读入。 【输出形式】 排版后的参演人员名单输出到当前目录下的listout.txt中。 【输入样例】 假设文件listin.txt内容为: Digital Intermediate by : EFILM Supervising Digital Colorist : STEVEN J. SCOTT Second Colorist :ANDREW FRANCIS Digital Intermediate Producer:LOAN PHAN Digital Intermediate Editor: DEVON MILLER 表示冒号固定位置的整数为: 40 【输出样例】 文件listout.txt中的内容应为: 【样例说明】 输入的文件listin.txt中有五行参演人员名单,要求排版后冒号":"位于第40个字符的位置,按照上述排版规则输出到文件listout.txt中。
最新发布
06-01

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值