Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Шаблоны фасадов и адаптеров для встраиваемых систем

Автор вопроса: Francisco RodríguezОтветов: 2

Прочитав книгу Элесиаса Уайта "Making Embedded Systems" (от O'Reilly), я запутался из-за этих двух терминов: фасады и шаблоны адаптеров. Объяснение, которое она дает обоим, совершенно непонятно.

Шаблон адаптера (стр. 19): "(... Иногда называется оболочкой) Преобразует интерфейс объекта в более простой для клиента ... Часто адаптеры написаны поверх программных API, чтобы скрыть уродливые интерфейсы ... ".

Узор фасада (стр. 86): "... Он обеспечивает упрощенный интерфейс для фрагмента кода ...". Затем он говорит ".. . Шаблон адаптера - это более общая версия шаблона фасада ".

К сожалению, оба термина кажутся мне похожими.

Исходя из других определений на этом (и других) сайтах, большинство людей говорят: "Шаблон адаптера обеспечивает совместимость двух несовместимых интерфейсов". Что в этом контексте означает слово "несовместимо"?

Большинство сайтов и книг дают свои определения шаблонов с более высокого уровня, отличного от точки зрения встроенной системы (простой C, а не ООП), поэтому приведенные примеры действительно не ясны.

Стоит упомянуть, что, хотя книга является отличным источником знаний как для новичков, так и для профессионалов, в нее не входило так много кода, поэтому следует выяснить такого рода определения.

Я попытался понять их с помощью пары примеров, которые я написал для себя, не могли бы вы указать мне, правильное мое понимание или нет?

Пример 1, узор фасада:

/* This is a fancy API that I want to 'facade' */

fancy_gui_DrawWidget(parent, id, x0, y0, x1, y1, text, txt_color, back_color, brdr_color, draw_callback(), ... and more parameters)
{
/* draw the widget */
}


/* Here I'm using the 'facade pattern' */

mygui_DrawButton(parent, id, x, y, width, height, text)
{
 ...
x1=x+width;
y1=y+height;
...

fancy_gui_DrawWidget(parent, id, x, y, x1, y1, text, BLACK, WHITE, ORANGE, button_draw_fn, ... and some more parameters needed);
}

Пример 2, шаблон адаптера:

/* Ugly interface that I want to 'adapt' (from LPC17xx NXP's CMSIS library) */

uint32_t UART_Send(
LPC_UART_TypeDef *UARTx,
uint8_t *txbuf,
uint32_t buflen,
TRANSFER_BLOCK_Type flag)
{
/* transmits the txbuf */
}

/* Here I'm using the 'adapter pattern' (I think so) for a good looking interface */

int uart0_Send(buffer, len_buffer)
{
/* Do some stuff */
len=UART_Send(uart0_handler,buffer,len_buffer, BLOCKING);
if(len!=len_buffer)
return 0;
return 1;
}

Надеюсь, я сам достаточно хорошо объяснил. Заранее благодарю!!

  • Добавьте шаблон Proxy, чтобы немного запутать себя :) haylem 03.07.2012

design-patternsembeddedadapterfacade

Ответы

Ответ 1 · рейтинг 2 · Brian Driscoll

Паттерн Фасад используется для абстрагирования сложной функциональности, чтобы упростить использование API.

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

ObjectA.update();
ObjectB.update();
ObjectC.update();

...и т.д...

Вы можете создать класс, который объединяет эти три вызова update () в один вызов:

SuperObject.update();

Это один из примеров фасада.

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

Допустим, у вашего необходимого интерфейса есть метод со следующей подписью:

void Save();

У вас уже есть класс, который реализует необходимое поведение, но не имеет необходимого интерфейса, возможно, примерно так:

bool Update();

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

void Save()
{
   bool notUsingThisReturnValue = existingClassInstance.Update();
}

Я написал статьи об использовании как паттерна фасада и шаблон адаптера

Ответ 2 · dbf

Франциско, ваш пример для адаптера верен. Я могу привести еще один, но он в основном объектно-ориентированный: представьте, что у вас есть интерфейс для источников данных, у всех есть метод int readValue(), и у вас есть интерфейс с этим методом для полиморфных вызовов. И у вас есть еще один устаревший старый, который вы не можете переписать (например, он управляется другой командой или он недоступен в исходном коде) с помощью метода int readInteger(). Вы не можете использовать ваш исходный интерфейс с readValue() методом для этого класса, поэтому вы создаете промежуточный класс, который имеет int readValue() метод, который делегирует void readInteger().

class Adapter implements Reader {
  private LegacyReader legacyReader;
  public int readValue() {
       return legacyReader.readInteger();
  }
}

Теперь вы можете использовать устаревшую программу чтения вместе с новыми классами и интерфейсом Reader.

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

Фасад обычно используется, когда у вас есть подробный API (например, drawCircle (), drawRect (), drawLine ()), но часто вам нужно использовать комбинацию этих вызовов, и вы хотите избежать копирования-вставки или не хотите для предоставления низкоуровневой абстракции клиентскому коду. В этом случае вы просто используете этот код:

class DrawerFacade {
   private LowLevelDrawer drawer;
   public void drawHouse(int i, int j) {
       drawer.drawCircle(...);
       drawer.drawRect(...);
   }
}

Вы можете использовать ту же концепцию с API функций (не-ООП) на простом C, если вы говорите о встроенных.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы