ESPNJimmy Butler's mission to return to the Warriors: 'I felt I let them down'ESPN DeportesRayados sufre ante Pachuca y regresa a zona de LiguillaThe Jerusalem PostLebanon must refuse Hezbollah’s demand to return seized explosives - editorialInquirerSenate to extend courtesy to OVP in budget hearing한겨레중국 문샷AI ‘17살 천재 연구원’ 퇴사…미 실리콘밸리행에 쏠리는 관심ZDF heuteAktuelle Pressemitteilungen des ZDFDaily MaverickPODCAST: Johannesburg’s junior mayor race put youth mental health and civic duty centre stageThe RegisterEngineer was so sick of office pranks, he 'wiped' his antagonist's disk경향신문‘구의회 정상화 촉구 단식’ 대전 대덕구청장 병원 이송···의회는 여전히 파행 중Il Sole 24 OreNuovo Codice della strada, corsia virtuale e protezioni obbligatorie in autostrada: le novità per i motociclistiComplete SportsEUROMATCH NPFL: We Had A Bad Day – Ogunbote Speaks On Plateau United’s Home Loss To Sporting LagosRappler[EDITORIAL] Cruelty is not wit — itigil ang disabled-shaming
The Daily Newsstand · Free, Always
Monday, October 19, 2026

[Перевод] Трюгве Реенскауг «Первоначальные отчеты по MVC»

Translate

Я создал первую реализацию MVC и написал соответствующие первоначальные отчеты в 1978/79 годах, будучи приглашенным научным сотрудником Исследовательской лаборатории Xerox в Пало-Альто (PARC). MVC возник как очевидное решение общей задачи: позволить пользователям управлять своей информацией, рассматривая ее с разных точек зрения. MVC вызвал неожиданно большой интерес. В некоторых текстах даже используются его искаженные варианты, преследующие прямо противоположную цель — заставить компьютер управлять пользователем.

MVC задумывался как общее решение задачи: позволить пользователям управлять большим и сложным набором данных. Труднее всего было подобрать удачные названия для различных архитектурных компонентов. Сперва появился набор Модель-Представление-Редактор (Model-View-Editor). Эти компоненты описаны в моей первой заметке от 12 мая 1979 года «ВЕЩЬ-МОДЕЛЬ-ПРЕДСТАВЛЕНИЕ-РЕДАКТОР: пример из planningsystem». Текст заметки приводится ниже.

После долгих обсуждений, особенно с Адель Голдберг, я остановился на терминах Модель-Представление-Контроллер (Model-View-Controller), как описано в моей второй заметке от 10 декабря 1979 года «МОДЕЛИ — ПРЕДСТАВЛЕНИЯ — КОНТРОЛЛЕРЫ». Текст заметки приводится в конце этого документа.

Джим Альтхофф с коллегами реализовали версию MVC для библиотеки классов Smalltalk-80 уже после того, как я покинул Xerox PARC; в этой работе я не участвовал.

Осло, 12 февраля 2007
Трюгве Реенскауг

ВЕЩЬ-МОДЕЛЬ-ПРЕДСТАВЛЕНИЕ-РЕДАКТОР: пример из planningsystem

Кому: LRG
От: Трюгве Реенскауга
Место хранения: [IVY]<Reenskaug>SMALL> TERMIN0LOGY2.DOC
Дата: 12 мая 1979

Цель этой заметки — исследовать метафоры вещь-модель-представление-редактор через связный набор примеров. Все примеры взяты из моей системы planningsystem и иллюстрируют четыре вышеупомянутых понятия. Все примеры были реализованы, хотя и не в рамках той чистой структуры классов, которая описана здесь. Эти метафоры соответствуют метафорам реальный мир-Модель-представление-Инструмент, предложенным в «Заметке о требованиях к DynaBook» ([Ivy]<Reenskaug>DynaBook.doc).

ВЕЩЬ

ОПРЕДЕЛЕНИЕ ТЕРМИНА

Нечто, представляющее интерес для пользователя. Это может быть что-то конкретное, например дом или интегральная схема. Это может быть что-то абстрактное, например новая идея или мнения о статье. Это может быть целое, например, компьютер, или часть, например, элемент схемы.

ПРИМЕР: КРУПНЫЙ ПРОЕКТ

Здесь Вещь — это крупный проект. Это может быть проектирование и строительство крупного моста, электростанции или морской нефтедобывающей платформы.Такие проекты представляют собой сложные задачи с огромным количеством взаимозависимых деталей. Ответственные за проект должны отслеживать все эти детали и их зависимости, чтобы понимать последствия различных реальных или предполагаемых ситуаций, которые могут возникнуть.

Для управления крупными проектами используется множество разнообразных абстракций. Каждая абстракция выделяет определенные аспекты проекта в целом и используется для управления этими аспектами сама по себе или вместе с другими абстракциями. Например, это то, как мы думаем о требованиях к материалам, об оценке стоимости, о различных теориях бюджетирования и бухгалтерского учета.

Одной из особенно полезных абстракций является понятие сети работ, или диаграммы PERT. Эта абстракция связывает воедино то, что должно быть сделано, с тем, кто должен это делать, и с тем, когда это должно быть сделано.

В абстракции сети каждая задача, которая должна быть выполнена в рамках проекта, отображается в виде простого элемента под названием работа. По сути, работа характеризуется продолжительностью и предшественниками. Продолжительность определяет время, необходимое для выполнения соответствующей работы, а предшественники — это работы, которые должны быть завершены, прежде чем текущая работа может быть начата.

Эту простую абстракцию обычно расширяют в нескольких направлениях. На основе предшественников легко найти последователей каждой работы. Начальные работы сети — это все работы, не имеющие предшественников, а конечные работы — это работы, не имеющие последователей. К каждой работе может быть добавлена и другая информация. Один пример — требования к ресурсам, другой — стоимость и финансовые потоки, связанные с этой работой.

МОДЕЛЬ

ОПРЕДЕЛЕНИЕ

Модель — это активная репрезентация абстракции в виде данных в вычислительной системе.

ЗАМЕЧАНИЯ

Как отмечалось выше, в общем случае существует множество различных способов абстрагирования одной и той же Вещи; поэтому часто полезно иметь несколько сосуществующих Моделей одной Вещи. Или же можно считать, что в проекте имеется одна большая Модель, подразделяющаяся на несколько Подмоделей.

В компьютере модели даны в виде совокупности данных и методов, необходимых для их обработки.

В идеале все модели должны быть полностью согласованными. Этот идеал недостижим на практике, поскольку для него потребовалась бы непомерная бюрократия и удушающая жесткость. Поэтому следует допустить некоторую несогласованность, стремясь к тому, чтобы вся совокупность моделей достаточно точно отражала проект, при этом не уделяя чрезмерного внимания несущественным деталям.

В нашем примере данная Модель сети отражена в системе Smalltalk в виде экземпляра класса NetworkModel. Каждая работа в этой Модели сети отражена в виде экземпляра класса Activity.

Одно из полей, определенных для класса NetworkModel, — activities, словарь (Dictionary), связывающий имена работ (значения UniqueString) с экземплярами Activity. Для класса Activity определены три поля: network, predecessors и successors. Поле network содержит указатель на соответствующий экземпляр NetworkModel, а predecessors и successors — это векторы (Vector), содержащие указатели на экземпляры Activity.

Таким образом, общая структура нашей Модели (= отражение модели сети проекта в Smalltalk) выглядит следующим образом:

Теперь в рамках этого общего подхода мы можем добавить информацию о нашем проекте, которую можно связать как с сетью в целом, так и с каждой ее работой. К сети мы можем, например, добавить поля plannedStart и plannedFinish. К определению класса Activity можно добавить поля duration, earlyStart, lateStart и resourceRequirements. Мы также можем добавить поля для позднего начала и позднего окончания, но при этом решить, что будем вычислять эти величины по мере необходимости. (Исходя из duration и earlyStart или lateStart.) 

Заметим, что Модель сети с ее подмоделями для каждой работы не содержит никакой информации о том, как ее можно отобразить на экране; это чистая репрезентация абстрактной модели проекта.

ПРЕДСТАВЛЕНИЕ

ОПРЕДЕЛЕНИЕ

С любой данной Моделью связано одно или несколько Представлений; каждое Представление способно выводить на экран и на бумажный носитель одно или несколько изображений Модели. Представление также может выполнять над Моделью операции, уместные для этого Представления.

ЗАМЕЧАНИЕ

Реализацию всех Представлений можно было бы упростить, если бы они основывались на метафорах Форма-Путь-Изображение.

ПРИМЕР 1: Список сетей

Это Представление принадлежит суперсети, то есть коллекции сетей. Следовательно, оно несколько выходит за рамки тех Моделей, которые мы обсуждали до сих пор, однако включено для полноты. Вот как выглядит список сетей.

Список сетей — экземпляр класса NetworkList, являющегося подклассом ListView.

У ListView есть поля, в которых он хранит свою рамку, список текстовых элементов и выделенные элементы из этого списка, если они есть. Он умеет отображать список на экране внутри рамки и реагирует на сообщения, запрашивающие прокрутку. Он понимает сообщение, запрашивающее элемент, расположенный в заданной точке внутри рамки, и сообщение, запрашивающее выделить заданный элемент.

Таким образом, ListView несколько похож на ListPane в текущей системе, но он не является подклассом Window и не может быть запланирован. Поэтому он должен зависеть от Редактора, который сообщает ему, где находится его рамка, и организует прокрутку. Одна из возможных последовательностей выделения такова: Редактор реагирует на курсор и запрашивает у ListView элемент, на который указывает курсор. Затем Редактор просит ListView и любые другие Представления выделить этот элемент. Такое разделение пользовательского интерфейса и фактического выполнения команд делает Редактор очень гибким.

Класс NetworkList опирается на базовую функциональность ListView. Он должен знать, что имеет дело со списком сетей, и уметь хранить такой список. Кроме того, он должен уметь выполнять команды, относящиеся к его Представлению. Мы рассмотрим только две такие команды: выдать имя выбранной сети и поручить Редактору редактировать заданную сеть.

ПРИМЕР 2: Список работ в сети

Список работ в сети — экземпляр класса ActivityList, являющегося подклассом ListView (описание этого общего класса см. выше).

Экземпляр класса ActivityList должен знать, к какой сети он принадлежит, и как получить список всех работ в этой сети. В нем нет особых команд, кроме общих механизмов выделения, которые предоставляет ListView.

ПРИМЕР 3: Представление атрибутов работы

Это текстовое отображение всех атрибутов работы — экземпляр класса ActivityText, являющегося подклассом TextView.

Класс TextView имеет поля, в которых хранятся его рамка и абзац текста. Он может показывать текст внутри своей рамки с переносом и понимает сообщения, запрашивающие прокрутку текста внутри рамки. Он также может сопоставлять заданные координаты с позициями внутри текста и выделять текст между заданными позициями. Кроме того, он понимает сообщения, запрашивающие выполнение различных операций на основе выделения, таких как replace, cut, paste, again и т.д.

Таким образом, класс TextView похож на текущий ParagraphEditor, однако каждое прямое взаимодействие с пользователем преобразуется в одно или несколько сообщений, чтобы класс мог работать вместе с другими Представлениями через Редактор, а также с разными Редакторами.

Класс ActivityText должен знать, как получить текст для заданной работы. Эту операцию удобно инициировать сообщением select, как правило, от Редактора. Он также должен уметь реагировать на сообщения о работе, инициированные пользователем через Редактор. Часть таких сообщений предназначена для изменения данных, отображаемых в Представлении; за это отвечает суперкласс TextView. Пожалуй, наиболее важная команда для самого ActivityText — это accept, запрашивающая Представление проверить свое текущее содержимое и передать эту информацию Модели сети для обновления атрибутов работы.

Это Представление можно значительно улучшить, если сделать его класс подклассом табличного Представления, а не сплошного текста, как сейчас.

ПРИМЕР 4: Диаграмма сети

Приведенная выше диаграмма — экземпляр класса DiagramView. Это единственный пример, где данные в Представлении нельзя полностью вывести из его Модели, и класс должен иметь поля, содержащие форму и положение всех фигур, поскольку эта информация не является частью самой Модели. (Существуют программы для автоматического позиционирования фигур внутри диаграммы, но мы полагаем, что какую-то часть придется править вручную.) Расположение каждой дуги можно вывести из зависимостей между работами; эту информацию можно извлечь из NetworkModel, когда это понадобится для отображения. Однако такая процедура будет работать очень медленно, поэтому мы предполагаем, что DiagramView хранит копию этой информации из соображений производительности.

Как и все другие Представления, DiagramView должен будет предоставить две операции, необходимые для выделения работы, а также операции, необходимые для прокрутки (на этот раз в двух измерениях). Кроме того, ему понадобятся некоторые операции над самим Представлением, связанные с позиционированием фигур на диаграмме. Другие операции связаны с Моделью сети, например, изменить зависимости работы или перенести работу из одной сети в другую.

ПРИМЕР 5: Вариант диаграммы сети

Это Представление — альтернатива предыдущему примеру. Фигуры меньше, а значит, на экране можно показать большую часть сети. Из-за малого размера фигуры печатать внутри нее имя работы нецелесообразно, поэтому пользователь должен получить эту информацию каким-то другим способом.

Диаграмма сети представлена на фоне с координатной сеткой. Этот фон применяется, когда пользователь размещает элементы диаграммы, а точки определяют допустимые положения фигур, обозначающих работы.

Это Представление можно реализовать как подкласс DiagramView, или же оба могут быть подклассами некоторого общего Представления. Однако в текущей реализации оба Представления могут попеременно генерироваться одним и тем же объектом: класс DiagramView имеет поле displayType, принимающее значения #large или #small, а различные методы отображения управляются этим полем. Сетка отображается на диаграмме с помощью отдельного метода.

ПРИМЕР 6: Диаграмма Ганта

Это Представление показывает работы по вертикальной оси, а время — по горизонтальной. В данном конкретном Представлении для каждой работы показано только одно расписание. Варьируя штриховку, можно легко добавить сведения о том, насколько каждая работа может смещаться во времени, не нарушая при этом общий график проекта.

Эта диаграмма — экземпляр класса GanttView, являющегося подклассом ChartView. ChartView знает о фоне диаграммы, включая ось с разметкой, координатную сетку и т.д. Он ничего не знает об информации, которая будет помещена на диаграмму, в данном случае — о горизонтальных полосах. Однако он помогает своим подклассам отображать эту информацию, предоставляя методы преобразования из любой внешней системы координат в координаты рамки диаграммы.

Класс GanttView понимает ряд сообщений от пользователя, чаще всего передаваемых через Редактор. Одно из таких сообщений — viewNetwork:; оно передает имя текущего NetworkModel. Он также может ответить на вопрос, какая работа соответствует полосе под заданной точкой диаграммы, и выделить полосу, соответствующую заданной работе. Кроме того, он может передавать связанные с этим конкретным Представлением операции над сетью и ее работами. Типичные операции связаны с изменением текущего расписания. Следует предусмотреть операции для планирования сети в целом (backload: и frontload:), для изменения расписания отдельной работы (plannedStart: и plannedFinish:) и для распространения последствий такого изменения к началу или концу сети.

NetworkModel должен уметь отвечать на ряд вопросов от GanttPane: он предоставляет список всех работ, расписание сети в целом и расписание каждой отдельной работы.

ПРИМЕР 7: Ресурсная диаграмма

Эта диаграмма показывает суммарные требования к ресурсам по всем работам в зависимости от времени. (Как правило, для каждого вида ресурсов имеется своя такая диаграмма.)

Указанная диаграмма — экземпляр класса ResourceView, являющегося еще одним подклассом DiagramView. Замечания относительно диаграммы Ганта применимы и к ней, однако идею выделения нужно продумать. Ответ представления на who: point? может быть множеством всех работ, требующих ресурсы во время, соответствующее значению x point. Реакцией на сообщение select: activity может быть выделение ресурсных требований этой конкретной работы. Ради симметрии было бы хорошо сочетать и то и другое и сделать возможным множественное выделение во всех Представлениях NetworkModel.

РЕДАКТОР

ОПРЕДЕЛЕНИЕ

Редактор — это интерфейс между пользователем и одним или несколькими Представлениями. Он предоставляет пользователю подходящую систему команд, например в виде меню, которые могут динамически изменяться в соответствии с текущим контекстом. Он координирует Представления и передает им командные сообщения.

ЗАМЕЧАНИЕ

Пользовательскую задачу часто удобнее выполнять, когда на экране одновременно присутствуют несколько Представлений. Пользователь захочет управлять этими Представлениями, указывая на них, выбирая в меню или каким-либо иным способом. Такие команды, как выделение, обычно применяются сразу к нескольким Представлениям. Назначение Редактора — установить и расположить заданный набор Представлений на экране, координировать их и предоставлять пользователю подходящий командный интерфейс.

ПРИМЕР 8: Рабочая область UserView

Это весьма общий Редактор, предоставляющий пользовательский интерфейс к любой части работающей системы Smalltalk, достижимой из глобальной переменной. Поэтому он может использоваться как интерфейс к Представлениям planningsystem, однако оставляет большую часть работы пользователю.

Поскольку этот Редактор всегда доступен, его используют для запуска более специализированных Редакторов и для выполнения команд, которые используются недостаточно часто, чтобы ради них стоило создавать отдельный Редактор. Один из примеров таких команд — выгрузка в файл всей базы данных.

ПРИМЕР 9: Воображаемый Редактор для планирования

Этот Редактор очень похож на предыдущий, но создан в среде демонстрационной сети. Поэтому сообщения к этой сети и всем ее работам можно вводить и выполнять их напрямую с помощью команды doit. В результате через этот Редактор становятся доступны полные протоколы сети и ее работ.

В таком виде Редактор не реализован. Он является частью более полного Редактора, показанного в следующем примере.

ПРИМЕР 10: Подредактор демонстрационного Редактора

Этот Редактор входит в состав более полного демонстрационного Редактора (см. следующий пример) и предназначен для работы в его контексте. (На иллюстрации к примеру 9 на самом деле показан тот же Редактор, прокрученный вверх.)

Редактор — экземпляр класса DemoEditor, являющегося подклассом TextEditor. Поэтому он позволяет набирать, хранить и редактировать обычные тексты. Более того, поскольку DemoEditor знает о демонстрационной сети anet и всех ее работах, любые сообщения, понимаемые этими объектами, можно вводить и выполнять их через команду doit.

Поскольку этот Редактор является частью более полного демонстрационного Редактора (см. следующий пример), мы можем выполнять более общие выражения вроде activity duration, где activity интерпретируется как текущая выделенная работа.

Другой вариант этого подредактора мог бы общаться с экземпляром подкласса ListView, сводя возможности пользователя к выполнению предопределенных команд и запрещая любое редактирование отображаемого текста.

ПРИМЕР 11: Демонстрационный Редактор

Внешний вид этого Редактора на экране показан ниже. Редактор используется для демонстрации того, что одна и та же Модель может отображаться через множество разных Представлений.

Демонстрационный Редактор реализован как экземпляр класса DemoEditor, являющегося подклассом PanedWindow. Каждая из его панелей — это подредактор, который взаимодействует со своим конкретным Представлением. Он также передает команды демонстрационному Редактору и получает команды от него.

МОДЕЛИ — ПРЕДСТАВЛЕНИЯ — КОНТРОЛЛЕРЫ

От: Трюгве Реенскауга
Дата: 10 декабря 1979

МОДЕЛИ

Модели репрезентируют знание. Модель может быть единичным объектом (не слишком интересно) или некоторой структурой объектов. Предложенная реализация работает со знаниями, репрезентированными в виде чего-то вроде семантических сетей (если я правильно понимаю Лору).

Должно существовать взаимно однозначное соответствие между моделью и ее частями, с одной стороны, и миром, данном в том виде, как его воспринимает владелец модели, — с другой. Поэтому узлы модели должны отражать четко определенную часть проблемы.

Все узлы модели должны относиться к одному уровню задачи; смешение проблемно-ориентированных узлов (например, записей в календаре) с деталями реализации (например, абзацами) сбивает с толку и считается плохой практикой.

ПРЕДСТАВЛЕНИЯ

Представление — это (визуальная) репрезентация модели. Как правило, оно выделяет одни атрибуты модели и скрывает другие. Таким образом, оно действует как фильтр отображения.

Представление связано со своей моделью (или ее частью) и получает необходимые для отображения данные у модели, задавая ей вопросы. Оно также может обновлять модель, отправляя ей соответствующие сообщения. Все эти вопросы и сообщения должны формулироваться в терминах модели; следовательно, представление должно знать семантику атрибутов модели, которую оно отображает. (Например, оно может запросить идентификатор модели и ожидать, что получит экземпляр Text, но не может предполагать, что сама модель принадлежит классу Text.)

КОНТРОЛЛЕРЫ

Контроллер — это связующее звено между пользователем и системой. Он обеспечивает поступление информации к пользователю, организуя все так, чтобы соответствующие представления сами отображались в нужных местах на экране. Он также предоставляет средства для передачи информации от пользователя, предлагая ему меню или другие способы ввода команд и данных. Контроллер принимает эту информацию от пользователя, переводит ее в соответствующие сообщения и передает их одному или нескольким представлениям.

Контроллер никогда не должен дополнять Представления. Например, он ни в коем случае не должен связывать представления узлов, рисуя между ними дуги.

И наоборот, представление никогда не должно знать о пользовательском вводе, таком как действия мышью и нажатия клавиш. Всегда должна быть возможность написать в контроллере метод, который отправляет представлениям сообщения, в точности воспроизводящие любую последовательность пользовательских команд.

РЕДАКТОРЫ

Контроллер связан со всеми своими представлениями; они называются частями контроллера. Некоторые представления имеют особый контроллер — редактор, который позволяет пользователю изменять информацию, отображаемую этим представлением. Такие редакторы могут вклиниваться в путь между контроллером и его представлением, выступая расширением контроллера. Как только процесс редактирования завершается, редактор удаляется из пути и выбрасывается.

Отметим, что редактор взаимодействует с пользователем через метафоры своего представления; поэтому он тесно связан с этим представлением. Контроллер получает доступ к редактору, запрашивая его у представления — другого подходящего источника нет.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.