Развертывайте разные типы спутников с помощью одной и той же ракеты!

Шаблон адаптера - это гибкий шаблон структурного проектирования, который позволяет соединять два объекта с разными интерфейсами. Простым примером является переходник от трехконтактной настенной розетки к двухконтактной розетке. Этот шаблон прост по своей конструкции, но эффективен в применении, поскольку он позволяет некогда несовместимым объектам взаимодействовать друг с другом.

Эта статья будет состоять из трех основных разделов - сначала мы рассмотрим реальные примеры использования паттерна «Медиатор». Затем мы разберемся с его UML-диаграммой и, наконец, применим наши знания к реализации на Go, где мы запускаем разные типы спутников с одной и той же ракетой, используя - спутниковый адаптер.

3… 2… 1… Зажигание!

Примеры из реального мира

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

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

Вот несколько примеров шаблона адаптера:

  • Розетки - розетки из Великобритании в Америку, из Америки в Европу или даже в Австралию! Розетки бывают самых разных форм и размеров по всему миру, поэтому, если вы собираетесь в путешествие, вам следует подумать о том, чтобы упаковать несколько адаптеров.
  • Преобразование данных. Допустим, у вас есть приложение для обработки данных, которое выводит результаты в формат XML. Если вам нужен другой формат данных, например JSON, вы можете создать адаптер, который преобразует данные XML в JSON.
  • Преобразование единиц. Работающее приложение может находиться в США и использовать запрещенный британский стандарт для записи вашей статистики. Если вы хотите расширить свой рынок до Европы, вы можете написать класс адаптера, который вместо этого включает и преобразует все ваши имперские единицы в метрическую систему.
  • Оболочка SDK. Если вы пытаетесь работать со старым комплектом разработки программного обеспечения (SDK), вы можете добавить адаптер (также называемый оболочкой), чтобы стандартизировать SDK для вашей установки.

Диаграмма UML

Помимо шаблона Singleton, шаблон Adapter имеет одну из самых простых диаграмм UML. Напомним, что в Go нет классов, поэтому вместо диаграммы классов мы будем ссылаться на диаграмму объектов.

Допустим, у нас есть некоторый Client код, который хочет выполнить какое-то methodB(), но он определил поведение только для methodA() (это похоже на желание подключить трехконтактную розетку к двухконтактной). Для выполнения methodB() Client имеет объект Adaptor, который реализует клиентский интерфейс для methodA().

Однако вместо применения methodA() Adaptor будет реализовывать логику, которая преобразует methodA() в methodB(). Adaptor имеет Adaptee для применения этого перевода. Вот и все!

Реализация в Go

Давайте немного поинтересуемся и представим, что у нас есть собственная многоразовая ракета SpaceX, способная запускать спутники в космос (я уверен, что Илон мог бы пощадить нас). Теперь SpaceX заключает контракты на множество различных типов спутников (наряду со своими собственными Starlink).

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

Примечание. Здесь будет какой-то спутниковый жаргон, но я обещаю, что он не унимает основных моментов адаптера!

Я отвлекся, давайте код! Сначала структура нашего проекта.

$ mkdir adapter-pattern-go
$ cd adapter-pattern-go
$ touch main.go rocket.go satellites.go satelliteAdapter.go

rocket.go

Хорошо, давайте сначала сделаем ракету. SpaceX использует ракету Falcon 9 для запуска своих спутников Starlink. Итак, ракета Falcon 9 будет служить нашим Client, у которого есть метод для вставки спутника в порт Starlink.

У нас также есть полезная нагрузка, которая принимает общий тип - изящный маленький трюк Go, который я изучил, пытаясь добавить к ракете разные типы спутников. Использование []interface{} действует как фрагмент, который может принимать любой тип, поэтому используйте его по своему усмотрению!

satellites.go

Наши falcon9Rocket будут развертывать разные типы спутников. Ожидается, что спутник Starlink, но SpaceX заключает контракты с множеством различных типов спутников для вывода на орбиту! Первый шаг - создать наш satellite interface в строке 5. Опять же, как SpaceX, мы ожидаем, что будем вставлять спутники в порты Starlink. Мы определяем метод insertSatelliteIntoStarlinkPort() для приема ссылки на falcon9Rocket, поскольку мы собираемся добавить его payload.

Следующие блоки кода стандартные, мы создаем спутник starlinkSatellite и спутник oco2 (расшифровывается как Orbiting Carbon Observatory-2). Затем мы создаем версию конструктора Go (также известную как простая фабрика) в строках 16–25.

Наконец, мы реализуем метод insertSatelliteIntoStarlinkPort(), принимая ссылку на starlinkSatellite в строке 27. Мы также принимаем falcon9Rocket в качестве нашего параметра, чтобы мы могли также добавить starlinkSatellite к payload. Я думаю, что это одна из областей, в которой Go имеет такой чистый подход к реализации интерфейса.

Обратите внимание на то, что oco2Satellite имеет свою собственную независимую функцию для вставки спутника. Что еще хуже, он ожидает порт OCO2 (на самом деле, он просто имеет другую сигнатуру / имя функции, чем спутник Starlink, для примера).

Как мы собираемся вставить спутник OCO2, когда мы ожидаем порт Starlink от нашей ракеты Falcon 9? Конечно, со спутниковым адаптером!

SatelliteAdapter.go

Наш oco2SatelliteAdapter - это наш Adaptor, который принимает ссылкуoco2Satelite как нашу Adaptee. Оттуда, когда мы вызываем insertSatelliteIntoStarlinkPort() из адаптера, мы фактически делаем перевод и вызываем метод для вставки спутника в порт OCO2.

Если это немного нечетко, посмотрите, как мы организуем эти три пакета вместе.

main.go

Здесь мы связываем все это воедино. Сначала мы создаем экземпляр нашего falcon9Rocket и распечатываем его payload, чтобы убедиться, что он пуст. Затем мы также создаем экземпляры наших спутников.

Мы можем сразу вставить starlinkSatellite в наш falcon9Rocket без проблем. Обратите внимание, что мы не могли сделать то же самое с oco2Satellite!

Вот где в игру вступает oco2SatelliteAdapter. Мы создаем новый адаптер, который принимает oco2Satellite. Ссылаясь на предыдущую логику в satelliteAdapter.go, мы вносим изменения так, чтобы в строке 22 мы могли вызывать insertSatelliteIntoStarlinkPort для oco2SatelliteAdapter. Наш адаптер работает!

Мы также получаем полезную нагрузку ракеты, чтобы убедиться, что мы добавили две ракеты для взлета. Если бы мы запустили эту программу с помощью команды go run *.go, мы бы получили:

Falcon 9 payload: []
Attaching satellite to Falcon 9 Rocket.
Starlink satellite is attached to Falcon 9 Rocket.
Attaching satellite to Falcon 9 Rocket.
Satellite adapter converts Starlink port to OCO2 port.
OCO2 satellite is attached to Falcon 9 Rocket.
Falcon 9 payload: [%!s(*main.starlinkSatellite=&{Starlink Satellite}) %!s(*main.oco2Satellite=&{OCO2 Satellite})]

БУМ! Теперь вы знаете, как использовать шаблон адаптера на ходу.

Надеюсь, вам понравилась эта статья. Есть много способов расширить этот пример, например, добавить шаблон Factory для динамического создания спутников, ракет и адаптеров для ваших потребностей в освоении космоса. Если вы видели что-то, что вам понравилось, или какие-либо разделы, о которых вы хотели бы получить дополнительную информацию, оставьте комментарий ниже! Спасибо за прочтение.