设计模式之工厂方法模式---factory method

模式的介绍

模式的定义

Define an interface for creating an object,but let subclassed decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类

模式的使用场景

  1. 工厂方法模式是new一个对象的替代品,也就是说所有采用new来生成一个对象的地方都可以使用工厂方法模式。但是这需要慎重的考虑是否要增加一个工厂类进行管理,因为这增加了代码的复杂度
  2. 需要灵活的,可扩展的框架时,可以考虑采用工厂方法模式。

模式的优缺点

优点

  • 良好的封装性,代码结构清晰
    一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或其它约束字符串)就可以了,不用知道创建对象的具体过程和细节,降低模块间的耦合。
  • 扩展性非常优秀
    在增加产品类的情况下,只要适当的修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”
  • 屏蔽产品类
    产品类的实现如何变化,调用者不需要关心,它只需要关心产品创建的接口。只要接口不变,系统中的上层模块就不要发生变化 。
  • 典型的解耦框架
    高层模块只需要知道产品的抽象类,其它的实现类都不用关心,符合迪米特法则,我们不需要就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;也符合里氏替换原则,使用产品子类替换产品父类,没有问题。

注意事项

UML类图

设计模式之工厂方法模式---factory method_第1张图片

角色介绍

Product:定义产品的共性,实现对事物最抽象的定义
ConcreteProduct: 具体产品类
Creator:抽象创建类,也就是抽象工厂类
ConcreteCreator: 具体的工厂类

模式的简单实现

定义一个抽象的英雄类,分别可以获取血量和魔法值:

/** * 抽象英雄类 */
public abstract class Hero {
    /** * 英雄的血量 */
    public abstract void getBlood();
    /** * 英雄的魔法值 */
    public abstract void getMagicPoint();
}

定义二个具体的英雄类,一个英雄火枪–Sniper类,一个英雄白牛–SpiritBreaker类:

设计模式之工厂方法模式---factory method_第2张图片

/** * 英雄火枪--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");
    }
}

设计模式之工厂方法模式---factory method_第3张图片

/** * 英雄白牛--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类图如下:

设计模式之工厂方法模式---factory method_第4张图片

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章 工厂方法模式

你可能感兴趣的:(设计模式,android,method,工厂模式,factory)