2012-07-02 37 views
1

通過Elecias White的書「製作嵌入式系統」(來自O'Reilly)讓我感到困惑,因爲這兩個術語:Facade和Adapter模式。她給出的解釋都不明確。面向嵌入式系統的適配器模式

適配器模式(PAG,19):「(...有時也被稱爲包裝)這一個對象的接口轉換成一個爲客戶更容易...通常情況下,適配器被改寫軟件API來隱藏難看的界面......「

外觀模式(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; 
} 

希望我解釋不夠好自己。先進的謝謝!

+0

拋出代理模式,讓自己更加迷惑:) – haylem

回答

2

Facade模式用來抽象掉複雜的功能,以使一個API更容易使用。

舉例來說,假設你有一些代碼,在一次更新多個對象:

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

...等...

你可以創建一個包裝這三個更新類()呼叫爲單個呼叫:

SuperObject.update(); 

這是門面的一個示例。

當您需要使用特定接口以及實現所需行爲但沒有所需接口的對象時,您將使用Adapter模式。

比方說,你需要的接口有以下簽名的方法:

void Save(); 

你有一個類已經實現必要的行爲,但沒有你需要的界面,或許是這樣的:

bool Update(); 

你不想改變使用它現有的類和風險斷碼,你也不希望重新發明輪子,所以你不是創建一個實現保存方法,但使用實例的包裝類你現有的班級:

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

我寫文章,介紹使用Facade Pattern都和Adapter Pattern

+1

在您的評論和示例之後,更有意義的說,「facade模式」是「包裝器」的同義詞,與書中的定義不同,因爲事實上,正如在我的示例#1中,用戶不需要填寫所有字段以便通過* fancy_gui_DrawWidget()*繪製按鈕,因此他使用的是更簡單的* mygui_DrawButton()*。 * mygui_DrawButton()*是「包裝」fancy_gui_DrawWidget()。我會檢查你的文章,但我想我是在正確的方向=) –

0

弗朗西斯科,你的適配器的例子是正確的。我可以給出另一個,但它主要是面向對象的:假設你有一個數據源的接口都有方法 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())時,通常會使用外觀,但通常您需要使用此調用的組合,並且您希望避免複製粘貼或不想爲客戶端代碼提供低級抽象。 在這種情況下,你只需使用此代碼:

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

,如果你是在談論嵌入您可以使用的功能(未OOP)API相同的概念在純C。

+0

所以我可能會理解「適配器模式」作爲某種轉換,從一個已經存在的簽名到另一個,或到另一個在某些情況下更有用。我很舒服,我不能在這種情況下使用「轉換」,但這讓我覺得更清楚。 –