尋找android中的設計模式(三)
-
尋找工廠模式
工廠模式的家族分四種:靜態工廠模式、簡單工廠模式、工廠方法模式、抽象工廠模式。
下面以開冒菜店爲例,假設我定義了一家冒菜店:
<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源碼當中是如何使用工廠模式的:
-
BitmapFactory中有很多創建位圖的靜態方法:(靜態工廠模式)
public static Bitmap decodeFile(String pathName, Options opts) {
public static Bitmap decodeResource(Resources res, int id, Options opts) {
-
原生聯繫人應用裏面很多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; }
可以看到子類都實現了該接口來創建需要的適配器。
-
電話所有者與聯繫人之間的交互。(抽象工廠模式)
根據定義找到接口定義:
/** * 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); }
其他SmsInteraction和CalendarInteraction也都創建了圖標。
-
-
總結
學完了工廠模式後,下面總結下目前涉及OO原則:
-
封裝變化
-
多用組合,少用繼承
-
針對接口編程,不針對實現編程
-
爲交互對象之間的鬆耦合設計而努力
-
類應該對擴展開發,對修改關閉
-
依賴抽象,不要依賴具體類
-