尋找android中的設計模式(三)



尋找android中的設計模式(三)



  1. 尋找工廠模式

    工廠模式的家族分四種:靜態工廠模式、簡單工廠模式、工廠方法模式、抽象工廠模式。

    下面以開冒菜店爲例,假設我定義了一家冒菜店:

    	<pre class="java" name="code">public class MaoCaiStore {
    	
    	public MaoCai sellMaoCai(String type) {
    		MaoCai maoCai = null;
    		if (type.equals("weila")) {
    			maoCai = new WeilaMaoCai();
    		} else if (type.equals("zhongla")) {
    			maoCai = new ZhonglaMaoCai();
    		} else if (type.equals("mala")) {
    			maoCai = new MalaMaoCai();
    		} else {
    			maoCai = new ZhonglaMaoCai();
    		}
    		maoCai.prepare();
    		maoCai.fire();
    		maoCai.addTiaoliao();
    		return maoCai;
    	}
    }

    
    

    可以看到,在sellMaoCai方法裏面會根據傳入參數不同而做不同口味的冒菜。這樣就違背了OO原則(單一原則,開閉原則等)如果增加一種口味的冒菜,就得修改裏面的代碼。看下靜態工廠模式的處理方式:

    public class StaticMaoCaiFactory {
    	public static MaoCai createMaoCai(String type){
    		MaoCai maoCai = null;
    		if (type.equals("weila")) {
    			maoCai = new WeilaMaoCai();
    		} else if (type.equals("zhongla")) {
    			maoCai = new ZhonglaMaoCai();
    		} else if (type.equals("mala")) {
    			maoCai = new MalaMaoCai();
    		} else {
    			maoCai = new ZhonglaMaoCai();
    		}
    		return maoCai;
    	}
    }
    public  class MaoCaiStore {
    	
    	public MaoCai sellMaoCai(String type) {
    		MaoCai maoCai = StaticMaoCaiFactory.createMaoCai(type);
    		maoCai.prepare();
    		maoCai.fire();
    		maoCai.addTiaoliao();
    		return maoCai;
    	}
    }

    可以看到比較簡單,只是將創建冒菜的工作交給了StaticMaoCaiFactory中的靜態方法。這樣的好處是增加一種口味的冒菜只要修改StaticMaoCaiFactory中的靜態方法即可,將冒菜店和創建冒菜隔離,冒菜店只負責拿到冒菜開始做就行,至於冒菜的來源不關心。

    下面看下簡單工廠模式是如何做的:

    public class SampleMaoCaiFactory {
    	public MaoCai createMaoCai(String type){
    		MaoCai maoCai = null;
    		if (type.equals("weila")) {
    			maoCai = new WeilaMaoCai();
    		} else if (type.equals("zhongla")) {
    			maoCai = new ZhonglaMaoCai();
    		} else if (type.equals("mala")) {
    			maoCai = new MalaMaoCai();
    		} else {
    			maoCai = new ZhonglaMaoCai();
    		}
    		return maoCai;
    	}
    }
    public  class MaoCaiStore {
    	private SampleMaoCaiFactory mSampleMaoCaiFactory;
    	public MaoCaiStore() {
    		mSampleMaoCaiFactory = new SampleMaoCaiFactory();
    	}
    	public MaoCai sellMaoCai(String type) {
    		MaoCai maoCai = mSampleMaoCaiFactory.createMaoCai(type);
    		maoCai.prepare();
    		maoCai.fire();
    		maoCai.addTiaoliao();
    		return maoCai;
    	}
    }

    可以看出createMaoCai不在是一個靜態方法,而是需要創建工廠對象才能調用。好處跟靜態工廠模式一樣,只不過這裏用組合的方式把工廠組合進來。

    下面看下工廠方法模式:

    定義:定義一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法模式把類實例化的過程推遲到子類。

    意思就是把創建冒菜的任務交給冒菜店的子類(各個分店:上海西安),如下:

    public abstract class MaoCaiStore {
    	public abstract MaoCai createMaoCai(String type);
    	
    	public MaoCai sellMaoCai(String type) {
    		MaoCai maoCai = createMaoCai(type);
    		maoCai.prepare();
    		maoCai.fire();
    		maoCai.addTiaoliao();
    		return maoCai;
    	}
    }
    public class ShanghaiMaoCaiStore extends MaoCaiStore {
    	
    	@Override
    	public MaoCai createMaoCai(String type) {
    		MaoCai maoCai = null;
    		if (type.equals("weila")) {
    			maoCai = new ShanghaiWeilaMaoCai();
    		} else if (type.equals("zhongla")) {
    			maoCai = new ShanghaiZhonglaMaoCai();
    		} else if (type.equals("mala")) {
    			maoCai = new ShanghaiMalaMaoCai();
    		} else {
    			maoCai = new ShanghaiZhonglaMaoCai();
    		}
    		return maoCai;
    	}
    
    }
    public class XianMaoCaiStore extends MaoCaiStore {
    
    	@Override
    	public MaoCai createMaoCai(String type) {
    		MaoCai maoCai = null;
    		if (type.equals("weila")) {
    			maoCai = new XianWeilaMaoCai();
    		} else if (type.equals("zhongla")) {
    			maoCai = new XianZhonglaMaoCai();
    		} else if (type.equals("mala")) {
    			maoCai = new XianMalaMaoCai();
    		} else {
    			maoCai = new XianZhonglaMaoCai();
    		}
    		return maoCai;
    	}
    
    }

    可以看到,上海分店的工廠專門製造上海口味的冒菜,西安分店的工廠專門製造西安口味的冒菜。再看下定義:定義一個創建對象的接口就是,這個方法:

    public abstract MaoCai createMaoCai(String type);

  最後看下,抽象工廠方法:


定義:提供一個接口,用於創建相關的或依賴對象的家族,而不需要明確指定具體類。


比如冒菜店提供的各種蔬菜和肉類必須由當地提供,上海得由上海原料工廠提供,西安得由西安原料工廠提供。


下面定義一個接口用來獲取蔬菜和肉:

public interface MaoCaiYuanliaoFactory {
	public void createShuCai();
	public void createRou();
}


上海原料工廠:

public class ShanghaiMaoCaiYuanliaoFactory implements MaoCaiYuanliaoFactory {

	@Override
	public void createShuCai() {
		System.out.println("獲取上海產的蔬菜");
	}

	@Override
	public void createRou() {
		System.out.println("獲取上海產的蔬菜");
	}

}


西安原料工廠:

public class XiAnMaoCaiYuanliaoFactory implements MaoCaiYuanliaoFactory {

	@Override
	public void createShuCai() {
		System.out.println("獲取西安產的蔬菜");
	}

	@Override
	public void createRou() {
		System.out.println("獲取西安產的肉");
	}

}

然後在各分店冒菜店裏面組合該冒菜原料工廠:

public class ShanghaiMaoCaiStore extends MaoCaiStore {
	private MaoCaiYuanliaoFactory maoCaiYuanliaoFactory = new ShanghaiMaoCaiYuanliaoFactory();

下面測試下,比如在上海冒菜店賣一份麻辣的冒菜:

	public static void main(String[] args) {
		ShanghaiMaoCaiStore shanghaiMaoCaiStore = new ShanghaiMaoCaiStore();
		shanghaiMaoCaiStore.sellMaoCai("mala");
	}

打印結果:

準備
獲取上海產的蔬菜
獲取上海產的蔬菜
開抄
加調料


下面尋找下android源碼當中是如何使用工廠模式的:


    1. BitmapFactory中有很多創建位圖的靜態方法:(靜態工廠模式)

      public static Bitmap decodeFile(String pathName, Options opts) {
      public static Bitmap decodeResource(Resources res, int id, Options opts) {

    2. 原生聯繫人應用裏面很多fragment裏面都有createListAdapter方法:(工廠方法模式)

      根據定義找到創建對象的接口:(父類ContactEntryListFragment裏面)

      protected abstract T createListAdapter();
      mAdapter = createListAdapter();
      找到子類的實現:

          @Override
          protected ContactListAdapter createListAdapter() {
              DefaultContactListAdapter adapter = new DefaultContactListAdapter(getContext());
              adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
              adapter.setDisplayPhotos(true);
              adapter.setPhotoPosition(
                      ContactListItemView.getDefaultPhotoPosition(/* opposite = */ false));
              return adapter;
          }
          @Override
          public JoinContactListAdapter createListAdapter() {
              JoinContactListAdapter adapter = new JoinContactListAdapter(getActivity());
              adapter.setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(true /* opposite */));
              return adapter;
          }

      可以看到子類都實現了該接口來創建需要的適配器。

    3. 電話所有者與聯繫人之間的交互。(抽象工廠模式)

      根據定義找到接口定義:

      /**
       * Represents a default interaction between the phone's owner and a contact
       */
      public interface ContactInteraction {
          Intent getIntent();
          long getInteractionDate();
          String getViewHeader(Context context);
          String getViewBody(Context context);
          String getViewFooter(Context context);
          Drawable getIcon(Context context);
          Drawable getBodyIcon(Context context);
          Drawable getFooterIcon(Context context);
          String getContentDescription(Context context);
          /** The resource id for the icon, if available. May be 0 if one is not available. */
          int getIconResourceId();
      }

      可以看到這麼多接口用來創建跟聯繫人相關的產品。具體創建哪些對象在實現類裏面提供。

      一般跟聯繫人的交互有通話、短信、日曆活動。如下:

      public class CalendarInteraction implements ContactInteraction {
      public class CallLogInteraction implements ContactInteraction {
      public class SmsInteraction implements ContactInteraction {

      上面三個實現類裏面實現了各種產品的創建,可以看到抽象工廠可以讓製造的相關產品組合起來。而且具體的實現類裏面用了工廠方法來創建產品。比如:

      CallLogInteraction中實現了圖標的創建:

          public Drawable getIcon(Context context) {
              return context.getResources().getDrawable(CALL_LOG_ICON_RES);
          }

      其他SmsInteractionCalendarInteraction也都創建了圖標。

  1. 總結

    學完了工廠模式後,下面總結下目前涉及OO原則:

    1. 封裝變化

    2. 多用組合,少用繼承

    3. 針對接口編程,不針對實現編程

    4. 爲交互對象之間的鬆耦合設計而努力

    5. 類應該對擴展開發,對修改關閉

    6. 依賴抽象,不要依賴具體類



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章