手把手教學,Android中的橋接模式

vr279228 8年前發布 | 6K 次閱讀 橋接模式 Android開發 移動開發

1.介紹

橋接模式,又稱為橋梁模式,是結構型設計模式之一。在現實生活中大家都知道“橋梁”是連接河道兩岸的主要交通樞紐,簡而言之其作用就是連接河流的兩邊,而我們的橋接模式與現實中的情況很相似,也是承擔著連接“兩邊”的作用。

2.使用場景

  • 如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承關系,可以通過橋接模式使他們在抽象層建立一個關聯關系。
  • 對于那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,也可以考慮使用橋接模式。
  • 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。

3.認識橋接模式

橋接模式角色圖

角色介紹

  • Abstraction : 抽象部分。
    該類保持一個對實現部分對象的引用,抽象部分中的方法需要調用實現部分的對象來實現,該類一般為抽象類。
  • RefinedAbstraction : 優化的抽象部分。
    抽象部分的具體實現,該類一般是對抽象部分的方法進行完善和擴展。
  • Implementor : 實現部分。
    可以為接口或抽象類,其方法不一定要與抽象部分中的一致,一般情況下是由實現部分提供基本的操作,而抽象部分定義的則是基于實現部分這些基本操作的業務方法。
  • ConcreteImplementorA/ConcreteImplementorB : 實現部分的具體實現。
    完善實現部分中方法定義的具體邏輯。
  • Client : 客戶類,客戶端程序。

從代碼上看

  • 實現部分的抽象接口
    public interface Implementor{
      //實現抽象部分的具體方法
      public void operationImpl();
    }
  • 實現具體部分的實現
    public class ConcreteImplementorA implements Implementor{
        @Override
       public void operationImpl(){
          //具體的實現
      }
    }
    public class ConcreteImplementorB implements Implementor{
        @Override
       public void operationImpl(){
          //具體的實現
      }
    }
  • 抽象部分的實現

    public absteact class Abstraction{
      //生命一個私有成員變量引用實現部分的對象
      private Implementor mImplementor;

    //通過實現部分對象的引用構造抽象部分的對象 public Abstraction (Implementor implementor) { mImplementor = implementor; }

    //通過調用實現部分具體的方法實現具體的功能 public void operation(){ mImplementor.operationImpl(); } }</code></pre> </li>

  • 抽象部分的子類

    public class RefinedAbstraction extends Abstraction{

    public RefinedAbstraction (Implementor implementor){ super(implementor); }

    //對父類抽象部分中的方法進行擴展 public void refinedOperation(){ //對Abstraction中的方法擴展 } }</code></pre> </li>

  • 客戶類
    public class Client{
      public static void main(String[] args){
          //客戶調用邏輯
      }
    }
  • </ul>

    簡單實現

    簡單設計一個場景,一般我們去吃牛排,服務員都會詢問你,吃什么牛排,要加什么汁,幾成熟。我們可以把“服務員”,“牛排”,“汁”,“幾成熟”定義為橋接模式的成員:

    • Client : 服務員
    • Abstraction : 加什么汁,要幾成熟
    • RefinedAbstractionA : 黑椒汁
    • RefinedAbstractionB : 七成熟
    • Implementor :吃什么牛排
    • ConcreteImplementorA : 服務員來一份菲力牛排(Filet Steak)
    • ConcreteImplementorB : 服務員再來一份西冷牛排(Sirloin Steak)

    Paste_Image.png

    代碼實現

    • Implementor
      public interface Steak {
        public void addSomething(String something);
      }
    • ConcreteImplementorA
      public class FiletSteak implements Steak {
        @Override    public void addSomething(String something) {
            Log.i("mytag",something);
       }
      }
    • ConcreteImplementorB
      public class SirloinSteak implements Steak {
        @Override
        public void addSomething(String something) {
            Log.i("mytag",something);
        }
      }
    • Abstraction

      public abstract class Orders {
        protected Steak impl;
        public Orders(Steak impl){
            this.impl = impl;
        }
       public void writeOrder(String something){
            this.impl.addSomething(something);
        }
      }
    • RefinedAbstractionA

      public class Sauce extends Orders{
        public Sauce(Steak impl) {
            super(impl);
        } 
       @Override
        public void writeOrder(String sauce) {
            super.writeOrder(sauce);
        }
      }
    • RefinedAbstractionB
      public class Cooked extends Orders {
        public Cooked(Steak impl) {
            super(impl);
        }
        @Override
        public void writeOrder(String cooked) {
            super.writeOrder(cooked);
        }
      }
    • Client
      //服務員出場Log.i("mytag","客官請問想吃什么牛排");
      //我選擇菲力牛排
      Steak steak = new FiletSteak();
      steak.addSomething("菲力牛排");
      Log.i("mytag","客官請問加什么汁");
      //我選擇黑椒汁
      Orders orders = new Sauce(steak);
      orders.writeOrder("黑椒汁");
      Log.i("mytag","客官請問要幾成熟");
      //7成最好吃
      orders = new Cooked(steak);
      orders.writeOrder("七成熟");
      //分隔線
      Log.i("mytag","-------------------------");
      //同理西冷牛排
      Log.i("mytag","客官請問還想吃什么牛排");
      steak = new SirloinSteak();
      steak.addSomething("西冷牛排");
      Log.i("mytag","客官請問加什么汁");
      orders = new Sauce(steak);
      orders.writeOrder("番茄汁");
      Log.i("mytag","客官請問要幾成熟");
      orders = new Cooked(steak);
      orders.writeOrder("全熟");

      編譯代碼:

    Paste_Image.png

    Android源碼中的橋接模式實現

    橋接模式在Android中應用得相當廣泛,但一般而言都是作用于大范圍的,我們可以在源碼中很多地方看到橋接模式的應用。例如我們常用的 AdapterAdapterView 之間就是一個橋接模式。

    首先ListAdapter.java:

    public interface ListAdapter extends Adapter{
         //繼承自Adapter,擴展了自己的兩個實現方法
         public boolean areAllItemsEnabled();
         boolean isEnabled(int position);
    }

    這里先來看一下父類AdapterView:

    public abstract class AdapterView<T extends Adapter> extends ViewGroup {
         //這里需要一個泛型的
        Adapter public abstract T getAdapter();
        public abstract void setAdapter(T adapter);
     }

    接著來看ListView的父類AbsListView,繼承自AdapterView

    public abstract class AbsListView extends AdapterView<ListAdapter>
         //繼承自AdapterView,并且指明了T為ListAdapter
         /** * The adapter containing the data to be displayed by this view */
         ListAdapter mAdapter;
         //代碼省略
         //這里實現了setAdapter的方法,實例了對實現化對象的引用
         public void setAdapter(ListAdapter adapter) {
         //這的adapter是從子類傳入上來,也就是listview,拿到了具體實現化的對象
         if (adapter != null) {
             mAdapterHasStableIds = mAdapter.hasStableIds();
             if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds &&   mCheckedIdStates == null) {
                 mCheckedIdStates = new LongSparseArray<Integer>();
             }
         }
         if (mCheckStates != null) {
             mCheckStates.clear();
        }
         if (mCheckedIdStates != null) {
             mCheckedIdStates.clear();
        }
     }

    大家都知道,構建一個listview,adapter中最重要的兩個方法,getCount()告知數量,getview()告知具體的view類型,接下來看看AbsListView作為一個視圖的集合是如何來根據實現化對象adapter來實現的具體的view呢?

    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
         //省略代碼
         //這里在加入window的時候,getCount()確定了集合的個數
         mDataChanged = true;
         mOldItemCount = mItemCount;
         mItemCount = mAdapter.getCount();

    }</code></pre>

    接著來看

    View obtainView(int position, boolean[] isScrap) {
         //代碼省略
         ?//這里根據位置顯示具體的view,return的child是從持有的實現對象mAdapter里面的具體實現的
         ?//方法getview來得到的。
         final View child = mAdapter.getView(position, scrapView, this);
         //代碼省略 return child;
     }

    接下來在ListView中,onMeasure調用了obtainView來確定寬高,在擴展自己的方法來排列這些view。知道了

    這些以后,我們來畫一個簡易的UML圖來看下:

    以上就是Android源碼中的橋接模式實現

    橋接模式的優缺點

    優點

    • 分離抽象和實現部分

      橋接模式分離了抽象和實現部分,從而極大地提高了系統的靈活性。 讓抽象部分和實現部分獨立開來,分別定義接口,這有助于對系統進行分層,從而產生更好的結構化的系統。 對于系統的高層部分,只需要知道抽象部分和實現部分的接口就可以了。

    • 靈活的擴展性

      由于橋接模式把抽象和實現部分分離開了,而且分別定義接口,這就使得抽象部分和實現部分可以分別獨立的擴展,而不會相互影響,從而大大的提高了系統的可擴展性。可動態切換實現。

      由于橋接模式把抽象和實現部分分離開了,那么在實現橋接的時候,就可以實現動態的選擇和使用具體的實現, 也就是說一個實現不再是固定的綁定在一個抽象接口上了,可以實現運行期間動態的切換實現 。

    缺點

    • 不容易設計

      對開發者要有一定的經驗要求。

     

     

    來自:http://www.jianshu.com/p/5bb60f943827

     

 本文由用戶 vr279228 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!