模式的介绍
模式的定义
Define an interface for creating an object,but let subclassed decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
模式的使用场景
- 工厂方法模式是new一个对象的替代品,也就是说所有采用new来生成一个对象的地方都可以使用工厂方法模式。但是这需要慎重的考虑是否要增加一个工厂类进行管理,因为这增加了代码的复杂度
- 需要灵活的,可扩展的框架时,可以考虑采用工厂方法模式。
模式的优缺点
优点
- 良好的封装性,代码结构清晰
一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或其它约束字符串)就可以了,不用知道创建对象的具体过程和细节,降低模块间的耦合。 - 扩展性非常优秀
在增加产品类的情况下,只要适当的修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化” - 屏蔽产品类
产品类的实现如何变化,调用者不需要关心,它只需要关心产品创建的接口。只要接口不变,系统中的上层模块就不要发生变化 。 - 典型的解耦框架
高层模块只需要知道产品的抽象类,其它的实现类都不用关心,符合迪米特法则,我们不需要就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;也符合里氏替换原则,使用产品子类替换产品父类,没有问题。
注意事项
UML类图
角色介绍
Product:定义产品的共性,实现对事物最抽象的定义
ConcreteProduct: 具体产品类
Creator:抽象创建类,也就是抽象工厂类
ConcreteCreator: 具体的工厂类
模式的简单实现
定义一个抽象的英雄类,分别可以获取血量和魔法值:
/**
* 抽象英雄类
*/
public abstract class Hero {
/**
* 英雄的血量
*/
public abstract void getBlood();
/**
* 英雄的魔法值
*/
public abstract void getMagicPoint();
}
定义二个具体的英雄类,一个英雄火枪–Sniper类,一个英雄白牛–SpiritBreaker类:
/**
* 英雄火枪--Sniper类
*/
public class Sniper extends Hero {
@Override
public void getBlood() {
// TODO Auto-generated method stub
System.out.println("火枪--Sniper blood is 2000");
}
@Override
public void getMagicPoint() {
// TODO Auto-generated method stub
System.out.println("火枪--Sniper magic point is 500");
}
}
/**
* 英雄白牛--SpiritBreaker类
*/
public class SpiritBreaker extends Hero{
@Override
public void getBlood() {
// TODO Auto-generated method stub
System.out.println("白牛--SpiritBreaker blood is 5000");
}
@Override
public void getMagicPoint() {
// TODO Auto-generated method stub
System.out.println("白牛--SpiritBreaker magic point is 1000");
}
}
定义一个抽象工厂类–AFactoryCreator:
public abstract class AFactoryCreator {
public abstract <T extends Hero> T creator(Class<T> c);
}
定义具体的工厂类–FactoryCreator
public class FactoryCreator extends AFactoryCreator{
@Override
public <T extends Hero> T creator(Class<T> c) {
// TODO Auto-generated method stub
Hero hero = null;
try {
hero = (Hero) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T) hero;
}
}
客户端的工厂方法模式应用:FactoryMethod
public class FactoryMethod {
public static void main(String[] args) {
// TODO Auto-generated method stub
AFactoryCreator creator = new FactoryCreator();
Hero sniper = creator.creator(Sniper.class);
sniper.getBlood();
sniper.getMagicPoint();
Hero spiritBreaker = creator.creator(SpiritBreaker.class);
spiritBreaker.getBlood();
spiritBreaker.getMagicPoint();
}
}
程序运行输出:
火枪--Sniper blood is 2000
火枪--Sniper magic point is 500
白牛--SpiritBreaker blood is 5000
白牛--SpiritBreaker magic point is 1000
简单工厂模式:
我们再看这个例子,可以发现AFactoryCreator类是不是用处不大,但是增加了一个类,会导致系统的复杂度和清晰度。对于一些简单的例子,我们可以直接把AFactoryCreator类去掉,将FactoryCreator类的creator改为static方法,使用会更加方便,简洁。
修改如下:
public class StaticFactory {
public static <T extends Hero> T creator(Class<T> c){
Hero hero = null;
try {
hero = (Hero)Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T)hero;
}
}
Client调用如下:
public class FactoryMethod {
public static void main(String[] args) {
// TODO Auto-generated method stub
Hero sniper = StaticFactory.creator(Sniper.class);
sniper.getBlood();
sniper.getMagicPoint();
Hero spiritBreaker = StaticFactory.creator(SpiritBreaker.class);
spiritBreaker.getBlood();
spiritBreaker.getMagicPoint();
}
}
上面就是简单工厂模式—Simple Factory Pattern ,也叫静态工厂模式,该方法应用广泛,非常的实用,缺点是工厂类扩展比较困难。
其UML类图如下:
Android源码中的模式实现
静态工厂模式
静态工厂模式在android源码中是随处可见的,这主要是体现了其使用的简单和实用。
(1)BitmapFactory类
/frameworks/base/graphics/java/android/graphics/BitmapFactory.java
一个这个类名,就知道是创建Bitmap的工厂类,当然用的是工厂模式了。
public class BitmapFactory {
..................................
public static Bitmap decodeFile(String pathName, Options opts) {
return decodeFile(pathName, opts, true);
}
public static Bitmap decodeFile(String pathName, Options opts, boolean consumeRights) {
Bitmap bm = null;
InputStream stream = null;
try {
stream = new FileInputStream(pathName);
bm = decodeStream(stream, null, opts, consumeRights);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
*/
Log.e("BitmapFactory", "Unable to decode stream: " + e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// do nothing here
}
}
}
return bm;
}
public static Bitmap decodeFile(String pathName) {
return decodeFile(pathName, null);
}
public static Bitmap decodeResourceStream(Resources res, TypedValue value,
InputStream is, Rect pad, Options opts) {
return decodeResourceStream(res, value, is, pad, opts, true);
}
public static Bitmap decodeResource(Resources res, int id, Options opts) {
return decodeResource(res, id, opts, true);
}
public static Bitmap decodeResource(Resources res, int id) {
return decodeResource(res, id, null, true);
}
public static Bitmap decodeResource(Resources res, int id, boolean consumeRights) {
return decodeResource(res, id, null, consumeRights);
}
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
return decodeByteArray(data, offset, length, opts, true);
}
public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
return decodeByteArray(data, offset, length, null, true);
}
public static Bitmap decodeByteArray(byte[] data, int offset, int length,
boolean consumeRights) {
return decodeByteArray(data, offset, length, null, consumeRights);
}
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
return decodeStream(is, outPadding, opts, true);
}
private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts, boolean consumeRights) {
// ASSERT(is != null);
byte [] tempStorage = null;
if (opts != null) tempStorage = opts.inTempStorage;
if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
return nativeDecodeStream(is, tempStorage, outPadding, opts, consumeRights);
}
public static Bitmap decodeStream(InputStream is) {
return decodeStream(is, null, null);
}
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
return decodeFileDescriptor(fd, outPadding, opts, true);
}
public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
return decodeFileDescriptor(fd, null, null);
}
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts, boolean consumeRights);
...............
}
这个样例,我们可以看到Bitmap工厂类非常方便的得到各自Bitmap对象,这才是静态工厂模式的精髓所以。
静态工厂模式与单例模式的组合
下面这个android样例中,我们可以看到静态工厂模式与单例模式组合使用,可以方便的得到唯一的对象:
源码是Camera应用:
packages/apps/SnapdragonCamera/src/com/android/camera/CameraManagerFactory.java
/**
* A factory class for {@link CameraManager}.
*/
public class CameraManagerFactory {
private static AndroidCameraManagerImpl sAndroidCameraManager;
/**
* Returns the android camera implementation of {@link CameraManager}.
*
* @return The {@link CameraManager} to control the camera device.
*/
public static synchronized CameraManager getAndroidCameraManager() {
if (sAndroidCameraManager == null) {
sAndroidCameraManager = new AndroidCameraManagerImpl();
}
return sAndroidCameraManager;
}
}
参考资料
(1). Android设计模式源码解析之工厂方法模式
https://github.com/hfreeman2008/android_design_patterns_analysis/tree/master/factory-method/AigeStudio
(2).设计模式之禅—第8章 工厂方法模式