adapter pattern 就是將一個類別的介面轉換成客戶希望的另一個介面,也就是讓原本不相容的介面一起工作。
舉例來說,假設有以下的需求
- 我希望每個shape類別都有顯示的行為
- 使用者不需要知道物件為甚麼形狀
public abstract class Shape { public abstract void Show(); } class Rectangle extends Shape { @Override public void Show() { System.out.println("Rectangle"); } } class Triangle extends Shape { @Override public void Show() { System.out.println("Triangle"); } }
UML圖會長這樣
可以很看出,Rectangle和Triangle繼承並實作了Shape
接著在此時又出現了一個需求,需要再多實作一個五芒星的圖型
可是我並不知道如何實作這個功能,所以請教了google 大神之後,我得到了一個第三方的sdk
他的功能很完整,不過實作方法有點不同,如下
public class FiveStar { public void FiveStarDisplay() { System.out.println("FiveStar"); } }
可以發現到,我現在必須使用if else 來判斷該怎麼顯示圖型
public static void showShap(Object shape) { if(shape instanceof Shape){ ((Shape)shape).Show(); } else if(shape instanceof FiveStar){ ((FiveStar)shape).FiveStarDisplay(); } }這是個悲劇的開始,客戶必須區分這是甚麼形狀,只要用到shape就必須多加if else 判斷,
並且或許在未來某天,還可能誤將 shape 轉型轉錯造成app crash。
那麼我們可以做甚麼來避免這場悲劇的發生呢?
先思考一個問題,怎麼做對我們最好?
如果我們有辦法將FiveStar視為Shape那是不是所有的問題都迎刃而解了呢?
可是該怎麼做呢?
看看下面的方式
class FiveStarAdapter extends Shape { private FiveStar star; @Override public void Show() { // TODO Auto-generated method stub star.FiveStarDisplay(); } }
我們將 FiveStar封裝在 FiveStarAdapter裡這樣既達到了實作五芒星的功能,又可以維持客戶不需要區分是甚麼形狀就可以使用,接著就可以把showShap改成這樣
public static void showShap(Shape shape) { shape.Show(); }
程式變得更加簡潔,而且更低耦合度了
結論
Adapter的實作方式就是建立一個具備所需介面的新類別(FiveStarAdapter),然後包裝原有的類別(FiveStar),如此就可以將原有的類別轉型成Shape
沒有留言:
張貼留言