適配器模式
適配器模式可以用于對不同的接口進行包裝以及提供統一的接口,或者是讓某一個對象看起來像是另一個類型的對象。在靜態類型的編程語言里,我們經常使用它去滿足類型系統的特點,但是在類似Ruby這樣的弱類型編程語言里,我們并不需要這么做。盡管如此,它對于我們來說還是有很多意義的。
當使用第三方類或者庫的時候,我們經常從這個例子開始(start out fine):
def find_nearest_restaurant(locator) locator.nearest(:restaurant, self.lat, self.lon)end
我們假設有一個針對locator的接口,但是如果我們想要find_nearest_restaurant能夠支持另一個庫呢?這個時候我們可能就會去嘗試添加新的特殊的場景的處理:
def find_nearest_restaurant(locator) if locator.is_a? GeoFish locator.nearest(:restaurant, self.lat, self.lon) elsif locator.is_a? ActsAsFound locator.find_food(:lat => self.lat, :lon => self.lon) else raise NotImplementedError, "#{locator.class.name} is not supported." endend
這是一個比較務實的解決方案?;蛟S我們也不再需要考慮去支持另一個庫了。也或許find_nearest_restaurant就是我們使用locator的唯一場景。
那假如你真的需要去支持一個新的locator,那又會是怎么樣的呢?那就是你有三個特定的場景。再假如你需要實現find_nearest_hospital方法呢?這樣你就需要在維護這三種特定的場景時去兼顧兩個不同的地方。當你覺得這種解決方案不再可行的時候,你就需要考慮適配器模式了。
在這個例子中,我們可以為GeoFish以及ActsAsFound編寫適配器,這樣的話,在我們的其他代碼中,我們就不需要了解我們當前正在使用的是哪個庫了:
def find_nearest_hospital(locator) locator.find :type => :hospital, :lat => self.lat, :lon => self.lonendlocator = GeoFishAdapter.new(geo_fish_locator)find_nearest_hospital(locator)
特意假設的例子就到此為止,接下來讓我們看看真實的代碼。
實例
今天一大早,你的leader就匆匆忙忙跑過來找到你:“快,快,緊急任務!最近ChinaJoy馬上就要開始了,老板要求提供一種直觀的方式,可以查看到我們新上線的游戲中每個服的在線人數?!?br />你看了看日期,不是吧!這哪里是馬上要開始了,分明是已經開始了!這怎么可能來得及呢?
“沒關系的?!蹦愕膌eader安慰你道:“功能其實很簡單的,接口都已經提供好了,你只需要調用一下就行了?!?br />好吧,你勉為其難地接受了,對于這種突如其來的新需求,你早已習慣。
你的leader向你具體描述了一下需求,你們的游戲目前有三個服,一服已經開放一段時間了,二服和三服都是新開的服。設計的接口非常輕便,你只需要調用Utility.online_player_count(Fixnum),傳入每個服對應的數值就可以獲取到相應服在線玩家的數量了,如一服傳入1,二服傳入2,三服則傳入3。如果你傳入了一個不存在的服,則會返回-1。然后你只要將得到的數據拼裝成XML就好,具體的顯示功能由你的leader來完成。
新聞熱點
疑難解答