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

沒有留言:
張貼留言