嵌入式系统的Facade vs Adapter模式

时间:2012-07-02 20:33:10

标签: design-patterns embedded adapter facade

阅读Elecias White的书“制作嵌入式系统”(来自O'Reilly)让我感到困惑,因为这两个术语:Facade和Adapter模式。她对两者的解释都不清楚。

适配器模式(Pag,19):“(...有时称为包装器)它将对象的接口转换为对客户端更容易的接口。通常,适配器是通过软件API编写的,以隐藏丑陋的界面......“

Facade Pattern (Pag.86):“......它为一段代码提供了简化的界面......”。然后它说 “......适配器模式是外观模式的更通用版本”

可悲的是,这两个词似乎与我相似。

从本网站(和其他网站)的其他定义中,大多数人都说“适配器模式使两个不兼容的接口兼容”。在此上下文中,“ 不兼容 ”这个词是什么意思?

大多数网站和书籍都提供了关于模式的定义,而不是嵌入式系统的观点(普通的C,而不是OOP),所以给出的例子确实不清楚。

值得一提的是,虽然这本书对于初学者和专业人士来说都是一个很好的知识来源,但它并没有包含那么多代码,所以应该找出这种定义。

我试图通过我为自己写的几个例子来理解它们,你会告诉我我的理解是否正确吗?

示例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;
}
希望我自己解释得足够好。谢谢你提前!!

2 个答案:

答案 0 :(得分:2)

Facade模式用于抽象出复杂的功能,以使API更易于使用。

例如,假设您有一些代码可以同时更新多个对象:

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

...等...

您可以创建一个将这三个update()调用包装成一个调用的类:

SuperObject.update();

这是立面的一个例子。

当您拥有需要使用的特定接口以及实现所需行为但没有所需接口的对象时,您将使用适配器模式。

假设您所需的接口有一个带有以下签名的方法:

void Save();

你有一个已经实现了必要行为的类,但没有你需要的接口,可能是这样的:

bool Update();

您不希望更改现有类并冒险破坏使用它的代码,也不想重新创建轮,因此您创建了一个实现Save方法的包装类,但使用现有类的实例:

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

我写过文章,概述Facade PatternAdapter Pattern的使用

答案 1 :(得分:0)

Francisco,你的适配器示例是正确的。我可以给另一个,但它主要是面向对象的:假设你有一个数据源接口都有方法 int readValue()并且您具有用于多态调用的此方法的接口。 而且你还有另外一个你无法重写的旧版本(例如,它由其他团队管理或者在源代码中不可用)和方法 int readInteger()。您不能将此原始界面与此readValue()方法一起用于此类,因此您可以创建具有int readValue()方法的中间类,该代理将委派给void readInteger()

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

现在,您可以将旧版阅读器与新类和界面阅读器一起使用。

在普通的C世界中,如果函数期望具有指向具有特定签名作为参数的函数的指针,则可以使用它,并且实现函数具有另一个签名。只需使用另一个具有正确签名的函数包装您的函数。

当您拥有详细的API(例如,drawCircle(),drawRect(),drawLine())时,通常会使用Facade,但通常需要使用此调用的组合,并且您希望避免复制粘贴或不要使用我不想为客户端代码提供低级抽象。 在这种情况下,您只需使用此代码:

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

如果你在谈论嵌入式,你可以在普通C中使用与函数(not-OOP)API相同的概念。