设计模式-工厂方法模式
android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类。
今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式。
工厂方法模式,Factory Method,简单的方式,不简单的应用。
1.意图
定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方式模式使一个类的实例化延迟到其子类。
热门词汇:虚构造器 延迟 创建对象 子类
2.结构图和代码
我们先看看标准的工厂方法结构图:
先抽象的产品类,抽象的工厂类,然后用客户端具体的工厂生产相应的具体的产品,但是客户端并不知道具体的产品是怎么生产的,生产的过程封装在工厂里。所以说,某种程度上,工厂方法模式改变了我们直接用new创建对象的方式,一个很好的开始,意义重大。
以ThreadFactory为例:
这张图其实和原本的结构图有细微的区别,那就是参数化得工厂,而且从业务意义上也有些不同,但是思想是一样的。
我们来看下具体的代码:
- //抽象产品
- public interface Runnable {
- public abstract void run();
- }
- //抽象工厂
- public interface ThreadFactory {
- Thread newThread(Runnable r);
- }
下面是具体的实现:
比如AsyncTask类中工厂的具体实现如下:
- //工厂实现类
- private static final ThreadFactory sThreadFactory = new ThreadFactory() {
- private final AtomicInteger mCount = new AtomicInteger(1);
- public Thread newThread(Runnable r) {
- return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
- }
- };
- //那么产品类在哪里呢?
- //做为参数Runnable r,我们可以创建千千万万个此系列的产品类
- //同理,我们可以创建另外类似的工厂,生产某种专门的线程,非常容易扩展
看到这里,我们一方面为它的生产便利性感叹,一方面又为没创建某类产品都要创建一个工厂而感到繁琐,所以我们下面介绍简单工厂,它的结构图如下:
简单工厂把抽象工厂去掉了,你就创建一个专门生产某类产品就好。在一些特定而又不负责的领域非常实用方便套用这个模式。
在android中的Connection类中使用到了这个类:
其中Connection这个抽象类,既充当抽象产品类,也充当具体工厂类。
因为这种情况下,我们往往需要的是马上生产子类,getConnection方法往往是静态的,所以简单工厂,也叫静态工厂方法。
我们看看代码如下:
- abstract class Connection{
- static Connection getConnection(
- Context context, HttpHost host, HttpHost proxy,
- RequestFeeder requestFeeder) {
- if (host.getSchemeName().equals("http")) {
- return new HttpConnection(context, host, requestFeeder);
- }
- // Otherwise, default to https
- return new HttpsConnection(context, host, proxy, requestFeeder);
- }
- }
这就是简单工厂,一个很简单的参数化工厂,真的很简单。
3.效果
1.创建型模式;
2.参数化工厂方法模式得到相应的对象;
3.为子类提供挂钩;
4.连接平行的类层次。
另外一个例子:
先假设要做这样的一个设计。设计一个Usb功能的接口,具有store(存储)和takeAlong(携带方便)两个行为。然后要设计两个产品,一个是 Phone(手机),另一个是Camera(照相机),很显然,它们都可以是 Usb的实现类。为了便于统一管理和创建,我们很容易就能设计出一个简单的工厂模式。
(1)普通的工厂方法
首先,我们可以画出相关的设计图:
代码实现如下:
定义Usb接口
- public interface Usb {
- void store();
- void takeAlong();
- }
Phone类
- public class Phone implements Usb {
- @Override
- public void store() {
- System.out.println("this is Phone usb!");
- }
- @Override
- public void takeAlong() {
- // TODO Auto-generated method stub
- }
- public void call() {
- //TODO
- }
- public void sms() {
- //TODO
- }
- }
Camera类
- public class Camera implements Usb {
- @Override
- public void store() {
- System.out.println("this is Camera usb!");
- }
- @Override
- public void takeAlong() {
- // TODO Auto-generated method stub
- }
- public void takePhotos() {
- //TODO
- }
- }
创建一个简单的工厂类UsbFactory1,负责生产
- /**
- * 普通工厂方法
- * 参数传递的字符串会出错
- * :正确创建对象
- *
- * @author xuzhaohu
- *
- */
- public class UsbFactory1 {
- public Usb produce(String type) {
- if ("phone".equals(type)) {
- return new Phone();
- } else if ("camera".equals(type)) {
- return new Camera();
- } else {
- System.out.println("请输入正确的类型!");
- return null;
- }
- }
- }
子类实例化通过工厂类去创建,如要创建camera,
- /*普通工厂方法**/
- UsbFactory1 factory1 = new UsbFactory1();
- Usb usb1 = factory1.produce("camera");//+phone
- usb1.store();
输出:this is Camera usb!
总结:实现了工厂模式的基本功能,但是需要传参去控制,会出现很多不确定的问题,可以在工厂类中定义不同产品的生产,就是如下介绍的工厂多方法生产。
(2)工厂多方法
只要在UsbFactory中再定制一下就行,业务更加分明
根据设计修改工厂类
- **
- * 多个工厂类方法
- *
- * @author xuzhaohu
- *
- */
- public class UsbFactory2 {
- public Usb producePhone() {
- return new Phone();
- }
- public Usb produceCamera() {
- return new Camera();
- }
- }
同样,要实例化某个子类对象,则可以这样去调用:
- /*多个工厂方法模式**/
- UsbFactory2 factory2 = new UsbFactory2();
- Usb usb2 = factory2.producePhone();//+camera
- usb2.store();
输出:this is Phone usb!
这样是不是让业务逻辑更加清晰了一些呢!
但是如果在多处都要调用生产的话,不能每次都通过实例化工厂类然后去生产吧,这时候可以怎么样呢?
对,可以通过类访问,在工厂类中加上static方法。
- /**
- * 静态工厂方法
- * :不需要实例
- *
- * @author xuzhaohu
- *
- */
- public class UsbFactory3 {
- public static Phone producePhone() {
- return new Phone();
- }
- public static Camera produceCamera() {
- return new Camera();
- }
- }
那么这时候可以直接不用实例化工厂类去访问了
- /*静态工厂方法模式**/
- Usb usb3 = UsbFactory3.producePhone();//+camera
- usb3.store();
输出:this is Phone usb!
这样就更加方便了一些。一般情况下,这样就基本能满足需求了,但是如果现在需求又要增加生产另外一个实现类产品Phone1,这时候肯定需要修改工厂类,在工厂类中增加一个新类型的生产Phone1方法。从设计的角度上讲,可能违背了 闭包(对扩展要开放对修改要关闭) 的设计原则,为了不违背这个原则,可以抽象工厂方法去设计,下面将讲到。
(3)抽象的工厂方法
为了不修改工厂中方法,我们可以对每个产品都创建相应工厂类去实现生产。这时候可以通过一个接口 Provider 去定义生产(produce)这个行为,然后让每个产品的工厂类都实现这个接口。这样如果有新的产品要生产的话只需要先实现一个工厂类就行。如下设计
生产接口Provider
- /**
- * 将工厂生产的行为写成接口独立
- *
- * @author xuzhaohu
- *
- */
- public interface Provider {
- Usb produce();
- }
每个产品都有自己的工厂
PhoneFactory工厂
- public class PhoneFactory implements Provider {
- @Override
- public Usb produce() {
- // TODO Auto-generated method stub
- return new Phone();
- }
- }
CameraFactory工厂
- public class CameraFactory implements Provider {
- @Override
- public Usb produce() {
- // TODO Auto-generated method stub
- return new Camera();
- }
- }
每一个产品可以根据自己的业务来去工厂生产产品,如要生产Camera
- /*抽象工厂方法模式**/
- /*1.扩展性好,不用修改源代码
- *2.添加一个实现USB接口的类+一个对应的实现Provider的工厂类**/
- Provider provider = new CameraFactory();
- Usb usb4 = provider.produce();
- usb4.store();
输出:this is Camera usb!