开发设计模式学习之桥接模式

    这周学习一种学习容易使用难的设计模式——桥接模式也称桥梁模式,这是结构性设计模式之一,可以将抽象部分与实现部分分离,使他们都可以独立变化。

关于桥接模式的应用场景,主要有以下三种:

  (1)如果一个系统需要在构件的抽象画角色和具体化角色之间增加更多灵活性,避免在两个层次之间建立静态的继承联系,而是通过桥接模式使他们在抽象层建立一个连接;

  (2)对于那些不希望使用继承关系,或因为多层继承导致系统类数量急剧增加的系统,也可以考虑使用桥接模式;

  (3)一个类存在两个独立变化的维度,且这两个维度都需要扩展;

桥接模式的结构设计主要分四部分,

  (1)抽象部分:该类保持一个对实现部分对象的引用,在抽象部分调用的方法实现,是通过实现部分对象调用其方法来实现,该类一般为抽象类;

  (2)优化的抽象部分(抽象部分的子类):抽象部分的具体实现,该类一般是对抽象部分的方法进行完善和扩展;

  (3)实现部分:可以是接口或抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分定义具体被使用到的操作方法,而抽象部分定义的则是实现部分中基本操作方法的执行流程所在的业务方法;

  (4)实现部分的具体实现(实现部分的子类):完善实现部分中方法定义的具体逻辑;

 

  在Android源码中,有很多涉及到桥接模式的案例,比如对于View的视图层和绘制层的功能划分,就是范围很广的应用体现,在ListView和ListAdapter的使用中,ListView作为AdapterView的子类,属于桥接模式中优化的抽象部分,那么AdapterView就作为抽象部分了,在AdapterView中有对Adapter对象的引用,因此Adapter便是实现部分,对于ListAdapter或者自定义Adapter由于继承自Adapter,则是实现部分的具体实现。

  这部分的逻辑很简单,在实现部分,也就是Adapter接口中定义了操作数据的具体方法,包括getCount()等熟知的方法。下面是源码部分

  1 public interface Adapter {
  2     /**
  3      * Register an observer that is called when changes happen to the data used by this adapter.
  4      *
  5      * @param observer the object that gets notified when the data set changes.
  6      */
  7     void registerDataSetObserver(DataSetObserver observer);
  8 
  9      10      * Unregister an observer that has previously been registered with this
 11      * adapter via {@link #registerDataSetObserver}.
 12  13  observer the object to unregister.
 14       15      unregisterDataSetObserver(DataSetObserver observer);
 16 
 17      18      * How many items are in the data set represented by this Adapter.
 19      * 
 20 @return Count of items.
 21       22     int getCount();   
 23     
 24      25      * Get the data item associated with the specified position in the data set.
 26  27  position Position of the item whose data we want within the adapter's 
 28      * data set.
 29  The data at the specified position.
 30       31     Object getItem( position);
 32     
 33      34      * Get the row id associated with the specified position in the list.
 35  36  position The position of the item within the adapter's data set whose row id we want.
 37  The id of the item at the specified position.
 38       39     long getItemId( 40     
 41      42      * Indicates whether the item ids are stable across changes to the
 43      * underlying data.
 44  45  True if the same id always refers to the same object.
 46       47     boolean hasStableIds();
 48     
 49      50      * Get a View that displays the data at the specified position in the data set. You can either
 51      * create a View manually or inflate it from an XML layout file. When the View is inflated,the
 52      * parent View (GridView,ListView...) will apply default layout parameters unless you use
 53      * { android.view.LayoutInflater#inflate(int,android.view.ViewGroup,boolean)}
 54      * to specify a root view and to prevent attachment to the root.
 55  56  position The position of the item within the adapter's data set of the item whose view
 57      *        we want.
 58  convertView The old view to reuse,if possible. Note: You should check that this view
 59      *        is non-null and of an appropriate type before using. If it is not possible to convert
 60      *        this view to display the correct data,this method can create a new view.
 61      *        Heterogeneous lists can specify their number of view types,so that this View is
 62      *        always of the right type (see { #getViewTypeCount()} and
 63      *        { #getItemViewType(int)}).
 64  parent The parent that this view will eventually be attached to
 65  A View corresponding to the data at the specified position.
 66       67     View getView( position,View convertView,ViewGroup parent);
 68 
 69      70      * An item view type that causes the { AdapterView} to ignore the item
 71      * view. For example,this can be used if the client does not want a
 72      * particular view to be given for conversion in
 73  #getView(int,View,ViewGroup)}.
 74  75 @see #getItemViewType(int)
 76  #getViewTypeCount()
 77       78     static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
 79     
 80      81      * Get the type of View that will be created by { #getView} for the specified item.
 82  83  position The position of the item within the adapter's data set whose view type we
 84      *        want.
 85  An integer representing the type of View. Two views should share the same type if one
 86      *         can be converted to the other in { #getView}. Note: Integers must be in the
 87      *         range 0 to { #getViewTypeCount} - 1. { #IGNORE_ITEM_VIEW_TYPE} can
 88      *         also be returned.
 89  #IGNORE_ITEM_VIEW_TYPE
 90       91     int getItemViewType( 92     
 93      94      * <p>
 95      * Returns the number of types of Views that will be created by
 96  #getView}. Each type represents a set of views that can be
 97      * converted in { #getView}. If the adapter always returns the same
 98      * type of View for all items,this method should return 1.
 99      * </p>
100 101      * This method will only be called when the adapter is set on the { AdapterView}.
102 103 104  The number of types of Views that will be created by this adapter
105      106      getViewTypeCount();
107     
108     int NO_SELECTION = Integer.MIN_VALUE;
109  
110      111       *  true if this adapter doesn't contain any data.  This is used to determine
112       * whether the empty view should be displayed.  A typical implementation will return
113       * getCount() == 0 but since getCount() includes the headers and footers,specialized
114       * adapters might want a different behavior.
115       116       isEmpty();
117 }

  对于实现部分的具体实现,最上层就是我们可以自定义的Adapter了,里边具体实现了getCount()等方法,这里不再过多说明;

  再看另一边的抽象部分,也就是AdapterView抽象类,在抽象部分定义了子类获取的Adapter对象,同时通过getAdapter()获取Adapter对象后调用其方法,从而实现AdapterView的内部业务。部分相关代码如下

 1 abstract class AdapterView<T extends Adapter> extends ViewGroup {
 2      3      * 此次省略部分代码
 4       5 
 6      7      * Returns the adapter currently associated with this widget.
 8  9  The adapter used to provide this view's content.
10      11     abstract T getAdapter();
12 
13     14      * Sets the adapter that provides the data and the views to represent the data
15      * in this widget.
16 17  adapter The adapter to use to create this view's content.
18      19      setAdapter(T adapter);
20 
21 
22     23      * Sets the view to show if the adapter is empty
24      25     @android.view.RemotableViewMethod
26      setEmptyView(View emptyView) {
27         mEmptyView = emptyView;
28 
29         // If not explicitly specified this view is important for accessibility.
30         if (emptyView != null
31                 && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
32             emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
33         }
34 
35         final T adapter = getAdapter();
36         boolean empty = ((adapter == null) || adapter.isEmpty());
37         updateEmptyStatus(empty);
38     }
39 
40 
41     @Override
42     void setFocusable( focusable) {
43         44         boolean empty = adapter == null || adapter.getCount() == 0;
45 
46         mDesiredFocusableState = focusable;
47         if (!focusable) {
48             mDesiredFocusableInTouchModeState = false49 50 
51         super.setFocusable(focusable && (!empty || isInFilterMode()));
52 53 
54 
55 56     void setFocusableInTouchMode(57         58         59 
60         mDesiredFocusableInTouchModeState =61         if (focusable) {
62             mDesiredFocusableState = true63 64 
65         super.setFocusableInTouchMode(focusable && (!empty ||66 67 
68      checkFocus() {
69         70         71         boolean focusable = !empty || isInFilterMode();
72          The order in which we set focusable in touch mode/focusable may matter
73          for the client,see View.setFocusableInTouchMode() comments for more
74          details
75         super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState);
76         super.setFocusable(focusable && mDesiredFocusableState);
77         if (mEmptyView != null) {
78             updateEmptyStatus((adapter == 79 80 81 
82 
83     84      * Gets the data associated with the specified position in the list.
85 86  position Which data to get
87  The data associated with the specified position in the list
88      89     public Object getItemAtPosition( position) {
90         T adapter =91         return (adapter == null || position < 0) ?  : adapter.getItem(position);
92 93 
94     long getItemIdAtPosition(95         T adapter =96         null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
97 98 }

  最后看一下优化的抽象部分,也就是ListView的相关内容,主要是实现了getAdapter()和setAdatper()方法,并对外提供setAdapter()设置适配器。这部分的相关源码如下,需要注意ListView的直接父类是AbsListView,在AbsListView中定义了ListAdapter对象mAdapter作为默认访问,而AbsListView才继承了AdapterView:

@RemoteView
 2 class ListView  AbsListView {
 3      4      * 部分代码已省略
 5       6 
 7          * Returns the adapter currently in use in this ListView. The returned adapter
     * might not be the same adapter passed to { #setAdapter(ListAdapter)} but
10      * might be a { WrapperListAdapter}.
11 12  The adapter currently used to display data in this ListView.
13  #setAdapter(ListAdapter)
15      17     public ListAdapter getAdapter() {
18         return mAdapter;
19 21     22      * Sets up this AbsListView to use a remote views adapter which connects to a RemoteViewsService
     * through the specified intent.
24  intent the intent used to identify the RemoteViewsService for the adapter to connect to.
25      26 27      setRemoteViewsAdapter(Intent intent) {
28         super.setRemoteViewsAdapter(intent);
29 30 
31          * Sets the data behind this ListView.
34      * The adapter passed to this method may be wrapped by a { WrapperListAdapter},35      * depending on the ListView features currently in use. For instance,adding
36      * headers and/or footers will cause the adapter to be wrapped.
 adapter The ListAdapter which is responsible for maintaining the
39      *        data backing this list and for producing a view to represent an
40      *        item in that data set.
42  #getAdapter() 
43      44 45      setAdapter(ListAdapter adapter) {
46         if (mAdapter != null && mDataSetObserver != 47             mAdapter.unregisterDataSetObserver(mDataSetObserver);
48 49 
50         resetList();
51         mRecycler.clear();
52 
53         if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 054             mAdapter = new HeaderViewListAdapter(mHeaderViewInfos,mFooterViewInfos,adapter);
55         } else {
56             mAdapter = adapter;
57 58 
59         mOldSelectedPosition = INVALID_POSITION;
60         mOldSelectedRowId = INVALID_ROW_ID;
61 
62          AbsListView#setAdapter will update choice mode states.
63         .setAdapter(adapter);
66             mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
67             mOldItemCount = mItemCount;
68             mItemCount = mAdapter.getCount();
69             checkFocus();
70 
71             mDataSetObserver =  AdapterDataSetObserver();
72             mAdapter.registerDataSetObserver(mDataSetObserver);
73 
74             mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
75 
76              position;
77              (mStackFromBottom) {
78                 position = lookForSelectablePosition(mItemCount - 1,);
79             } 80                 position = lookForSelectablePosition(0,1)">81             }
82             setSelectedPositionInt(position);
83             setNextSelectedPositionInt(position);
84 
85             if (mItemCount == 086                  Nothing selected
                checkSelectionChanged();
88 89         } 90             mAreAllItemsSelectable = 91 92             93             checkSelectionChanged();
94 95 
96         requestLayout();
98 }

 

简言归纳一下桥接模式,实现部分定义操作方法,抽象部分定义操作的流程方法,其中,抽象部分持有实现部分的对象引用。各自的实现类实现他们的方法逻辑。

 

相关文章

文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win1...
文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由main...
文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件...
文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项...
文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上...
文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供...