diff --git a/API.ru.html b/API.ru.html index dd5328e..7d94a9f 100644 --- a/API.ru.html +++ b/API.ru.html @@ -352,6 +352,29 @@

В пределе в сложном api должна сложиться ситуация, при которой все объекты взаимодействуют друг с другом только как интерфейсы — нет ни одной публичной сигнатуры, принимающей конкретный объект, а не его интерфейс. Разумеется, достичь такого уровня абстракции практически невозможно - почти в любой системе есть глобальные объекты, разнообразные технические сущности (имплементации стандартных структур данных, например); наконец, невозможно «спрятать» за интерфейсы системные объекты.

+

Информационные контексты

+ +

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

+ +

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

+ +

Мы уже отмечали, что одним из недостатков нашей первой "наивной" реализации api была необходимость объекту source "знать" о том, как осуществляется преобразование данных (геокоординат в пиксели). Если это правило обобщить, оно будет выглядеть следующим образом:

+ + + +

Из этих правил явно следует, что в нашей системе source имеет право оперировать только географическими координатами, а оверлей - только пиксельными. Оперировать и теми, и другими имеет право только объект, реализующий оба интерфейса IGeoContext и IGraphicalContext, то есть Map. Аналогично, source имеет право оперировать только свойствами реальных транспортных средств (идентификационный номер), оверлей - только свойствами их графического представления (иконка, её размер), и только Vehicle может связать идентификатор объекта со свойствами его графического представления.

+ +

Достаточно внимательный читатель в этом месте может заметить, что правило информационной иерархии всё равно нарушается: объект высшего уровня Map оперирует данными низшего уровня абстракции - пикселями сцены, и будет совершенно прав. Конечно, в нашем умозрительном примере это совершенно излишне, но в реальном "большом" api карту от этого знания необходимо избавить.

+ +

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

+ +

Назовем такую сущностью, скажем, IRenderingEngine; в нашей иерархии это. Интерфейс займёт промежуточное положение между картой и графическими объектами. Тогда ответственностью карты как IGraphicalContext будет предоставление доступа к своему rendering engine; соответственно, оверлей будет работать уже не с IGraphicalContext, а именно с engine; связывание же оверлея с его графическим контекстом должен произвести тот, кто оверлей инстанцирует - в нашей системе это может быть либо vehicle, либо сам графический контекст, либо какая-то третья сущность, которую мы выделим специально для этого.

+ +

Дерево информационных контекстов (какой объект обладает какой информацией, и кто является транслятором из одного контекста в другой), по сути, представляет собой "срез" нашего дерева иерархии интерфейсов; выделение такого среза позволяет проще и удобнее удерживать в голове всю архитектуру проекта.

+