Skip to content

Что такое паттерн "Мембрана"

Published: at 12:00 AMSuggest Changes

Если обратиться к репозиторию фреймворка Vue, найти там раздел packages и зайти в модуль reactivity, вы обнаружите небольшой дисклеймер: “Имплементация этого модуля вдохновлена следующими образцами искусства экосистемы JavaScript”. Далее следуют три ссылки: 1) на библиотеку Meteor Tracker, имеющую, к слову, 44 тыс. звезд на гитхаб, и все еще активно поддерживаемую разработчиками; 2) на утилиту поскромнее (всего 1200 звезд на гитхаб) - nx-js/observer-util; и 3) на совсем скромную либу с 400+ звездами - Observable Membrane.

Что их объединяет? И почему сам Эван Ю, создатель фреймворка Vue.js, вдохновлялся этими библиотеками?

Все три примера “искусства экосистемы JavaScript” так или иначе реализуют паттерн, с которым вы сталкиваетесь каждый день, но название которого, возможно, ни разу не слышали.

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

Изоляция подсистем приложения с помощью мембран

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

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

Изоляция приложения или изоляция подсистем

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

Мембраны - это безопасный программный шаблон, который достигает подобного рода изоляции, но внутри одного приложения, а не между разными приложениями. Название «мембрана» подразумевает аналогию с клеточными мембранами, которые защищают внутренности клетки от хаотичной внешней среды, одновременно позволяя регулированное взаимодействие с ней.

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

Мембрана - это контролируемый периметр вокруг одного или нескольких объектов, обычно реализуемый через прокси или «объекты-обёртки». В типичной настройке мембраны периметр начинается с одного корневого объекта. Например, код на веб-странице может обернуть объект window в прокси мембраны. Этот прокси затем может быть передан во встроенный скрипт:

Схема мембраны с window proxy

Свойства мембраны

Мембраны прозрачны и в основном сохраняют поведение

Прокси мембраны обычно проектируются так, чтобы быть прозрачными: для клиента взаимодействие с прокси выглядит так же, как взаимодействие с обёрнутым объектом.

Однако, под «прозрачным» обычно понимают не абсолютную неотличимость, а то, что мембрана может выполнять некоторую дополнительную логику, когда сторонний код взаимодействует с обёрнутым объектом. Эта логика часто реализует некоторую «деформацию» поведения обёрнутого объекта - например, хост-страница может заменить некоторые операции реального window на менее чувствительные заглушки.

Транзитивное вмешательство мембраны

Использование прокси как обёрток над другими объектами - распространённый дизайн в объектно-ориентированных языках. Но что делает мембрану особенной - так это то, что любой объект, проходящий через мембрану, транзитивно оборачивается другим прокси-объектом (обычно с той же логикой).

Например, если window обёрнут мембраной, то при доступе к window.document вернётся прокси для соответствующего объекта Document.

Транзитивное обёртывание объектов

Сохранение идентичности

Во многих языках объекты имеют идентичность — например, в JavaScript оператор === проверяет, указывают ли две ссылки на один и тот же объект. Обычно мы хотим, чтобы мембрана сохраняла эту идентичность по обе стороны мембраны: если две ссылки указывают на один и тот же объект до обёртывания, то их обёрнутые версии также должны указывать на один и тот же прокси-объект.

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

Примеры использования мембран в реальности

В следующий раз разберемся, как этот паттерн используется во Vue.js для реализации модуля реактивности.

Подписывайтесь на мои соцсети по ссылкам ниже, чтобы оставаться на связи!

Подписывайтесь на мои соцсети: