В Smalltalk-80 для построения интерфейсов пользователя применяется тройка классов модель/вид/контроллер (Model/View/Controller - MVC).
MVC состоит из объектов трех видов:
- Модель - это объект приложения.
- Вид - экранное представление.
- Контроллер описывает, как интерфейс реагирует на управляющие воздействия пользователя.
МVC отделяет вид от модели, устанавливая между ними протокол взаимодействия «подписка/оповещение». Вид должен гарантировать, что внешнее представление отражает состояние модели. При каждом изменении внутренних данных модель оповещает все зависящие от нее виды, в результате чего вид обновляет себя. Такой подход позволяет присоединить к одной модели несколько видов, обеспечив тем самым различные представления. Можно создать новый вид, не переписывая модель.
Модель оповещает свои виды при каждом изменении значений данных, а виды обращаются к модели для получения новых значений.
На первый взгляд, в этом примере продемонстрирован просто дизайн, отделяющий вид от модели. Но тот же принцип применим и к более общей задаче: разделение объектов таким образом, что изменение одного отражается сразу на нескольких других, причем изменившийся объект не имеет информации о деталях реализации объектов, на которые он оказал воздействие. Этот более общий подход описывается паттерном проектирования наблюдатель.
Еще одно свойство MVC заключается в том, что виды могут быть вложенными. Например, панель управления, состоящую из кнопок, допустимо представить как составной вид, содержащий вложенные, - по одной кнопке на каждый. Пользовательский интерфейс инспектора объектов может состоять из вложенных видов, используемых также и в отладчике. MVC поддерживает вложенные виды с помощью класса CompositeView, являющегося подклассом View. Объекты класса CompositeView ведут себя так же, как объекты класса View, поэтому могут использоваться всюду, где и виды. Но еще они могут содержать вложенные виды и управлять ими. Здесь можно было бы считать, что этот дизайн позволяет обращаться с составным видом, как с любым из его компонентов. Но тот же дизайн применим и в ситуации, когда мы хотим иметь возможность группировать объекты и рассматривать группу как отдельный объект. Такой подход описывается паттерном компоновщик. Он позволяет создавать иерархию классов, в которой некоторые подклассы определяют примитивные объекты (например, Button - кнопка), а другие - составные объекты (CompositeView), группирующие примитивы в более сложные структуры.
MVC позволяет также изменять реакцию вида на действия пользователя. При этом визуальное представление остается прежним. Например, можно изменить реакцию на нажатие клавиши или использовать всплывающие меню вместо командных клавиш. MVC инкапсулирует механизм определения реакции в объекте Controller. Существует иерархия классов контроллеров, и это позволяет без труда создать новый контроллер как вариант уже существующего. Вид пользуется экземпляром класса, производного от Controller, для реализации конкретной стратегии реагирования. Чтобы реализовать иную стратегию, нужно просто подставить другой контроллер. Можно даже заменить контроллер вида во время выполнения программы, изменив тем самым реакцию на действия пользователя. Например, вид можно деактивировать, так что он вообще не будет ни на что реагировать, если передать ему контроллер, игнорирующий события ввода.
MVC позволяет также изменять реакцию вида на действия пользователя. При этом визуальное представление остается прежним. Например, можно изменить реакцию на нажатие клавиши или использовать всплывающие меню вместо командных клавиш. MVC инкапсулирует механизм определения реакции в объекте Controller. Существует иерархия классов контроллеров, и это позволяет без труда создать новый контроллер как вариант уже существующего. Вид пользуется экземпляром класса, производного от Controller, для реализации конкретной стратегии реагирования. Чтобы реализовать иную стратегию, нужно просто подставить другой контроллер. Можно даже заменить контроллер вида во время выполнения программы, изменив тем самым реакцию на действия пользователя. Например, вид можно деактивировать, так что он вообще не будет ни на что реагировать, если передать ему контроллер, игнорирующий события ввода.
Отношение вид-контроллер - это пример паттерна проектирования стратегия. Стратегия - это объект для представления алгоритма. Он полезен, когда вы хотите статически или динамически подменить один алгоритм другим, если существует много вариантов одного алгоритма или когда с алгоритмом связаны сложные структуры данных, которые хотелось бы инкапсулировать.
В MVC используются и другие паттерны проектирования, например фабричный метод, позволяющий задать для вида класс контроллера по умолчанию, и декоратор для добавления к виду возможности прокрутки. Но основные отношения в схеме MVC описываются паттернами наблюдатель, компоновщик и стратегия.