寻找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原则:
-
封装变化
-
多用组合,少用继承
-
针对接口编程,不针对实现编程
-
为交互对象之间的松耦合设计而努力
-
类应该对扩展开发,对修改关闭
-
依赖抽象,不要依赖具体类
-