Design Patterns in Android:工厂方法模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Xiong_IT/article/details/54575488

前言

今天给大家分享的是《设计模式Android篇:工厂方法模式》。
工厂方法是创建型模式的一种,可用来在适当的场合创建对象。今天将通过Android源码和Android开发案例跟大家讲解什么是工厂方法模式。
点击此处查看《Design Patterns in Android》系列其他文章。

本文原创作者MichaelX,博客链接:http://blog.csdn.net/xiong_it,转载请注明出处。


工厂方法模式定义

工厂方法模式(Factory method pattern)定义一个接口用于创建对象,但是让子类决定初始化哪个类。工厂方法把一个类的初始化下放到子类。


工厂方法模式UML类图

工厂方法模式UML类图

工厂方法各角色讲解

  • IFactory:工厂接口,生产IProduct实例
  • IProduct:产品接口/抽象类
  • FactoryA:生产ProductA产品
  • FactoryB:生产ProductB产品
  • ProductA:一种产品,代号为A

工厂方法模式示例代码

IFactory

public interface IFactory {
    IProduct create();
}

IProduct

public interface IProduct {
    void doSomething();
}

ProductA

public class ProductA implements IProduct {

    @Override
    public void doSomething() {
        System.out.println("lalala...我是IProduct的实现类A。");
    }

}

FactoryA

public class implements IFactory {
    public IProduct create() {
        return new ProductA();
    }

}

但是:上述的标准的工厂方法模式通常伴随着对象的具体类型与工厂具体类型的一一对应,客户端代码根据需要选择合适的具体类型工厂使用,这种选择可能包含复杂的逻辑。

就好比说,我有10种产品,到生产的时候,你要我高层模块去根据产品选择合适的工厂来生产吗?所以就应运而生了一种-简单工厂模式:简单工厂类有一个静态工厂方法,可以根据高层模块的输入参数而生产合适的产品返回,比如:

public class SimpleFactory {

    public static  <T extends IProduct> T create(Class<T> clazz) {
        IProduct product = null;
        try {
            product = (IProduct) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return (T) product;
    }
}

上述的简单工厂例子中使用了Class作为输入参数,这是不固定,参数也可以是其他,大家根绝场景自定义。

Android源码中的工厂方法模式

暂时未在Framework常用类中找到很纯粹的工厂方法模式,此处待补充。有同学知道的请留言,谢谢!


Android开发中的工厂方法模式实践

假如:你在项目中使用了Universal Image Loader作为图片加载框架,过一段时间后,发现UIL已经不流行了,想用更加fashion的Glide来代替土老帽UIL。咋办?新手程序员,可能就想,既然这样,那就改呗,所有用到UIL的地方,统统抛掉,抛掉。项目小还好,改吧改吧就完了,项目大点,改坏了咋整?版本回退?可惜的是,很多新手程序员可能连版本控制不用。万一要是哪一天,连Glide都不更新了,或者说不fashion了,又要换其他图片加载框架,难道又改吗?人都要疯了好吗?

这个时候,工厂方法可能可以帮上忙:使用工厂类隔离图片加载的具体实现,对外只暴露一个工厂方法用来外部生产想要的加载框架实例,就可避免上述提到的尴尬。口说无凭,上代码:

图片加载接口

/**
 * 图片加载接口
 */
public interface ImageLoaderInterf {
    interface CallBack {
        void onSuccess(Bitmap result);
        void onFailure();
    }

    void load(Context context, String imgUrl, ImageView view);
}

图片加载工厂类

public class ImgLoaderClientFactory {
    public static final GLIDE = 0;
    public static final UIL = 1;
    public static final PICASSO = 2;

    public static ImageLoaderInterf getImageLoaderClient(int type) {
        switch (type) {
            case GLIDE:
                return GlideClient.getInstance();

            case UIL:
                return UilClient.getInstance();

            default:
                return PicassoClient.getInstance();
        }
    }
}

UilClient:Universal Image Loader封装

public class UilClient implements ImageLoaderInterf {

    private static UilClient sInstance;

    private UilClient() {}

    public static UilClient getInstance() {
        synchronized (UilClient.class) {
            if (sInstance == null) {
                sInstance = new UilClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        ImageLoader.getInstance().displayImage(imgUrl, view);
    }
}

GlideClient:Glide的二次封装

public class GlideClient implements ImageLoaderInterf {
    private static GlideClient sInstance;

    private GlideClient() {}

    public static GlideClient getInstance() {
        synchronized (GlideClient.class) {
            if (sInstance == null) {
                sInstance = new GlideClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        Glide.with(context).load(imgUrl).into(view);
    }
}

PicassoClient:Picasso封装类

public class PicassoClient implements ImageLoaderInterf {

    private static PicassoClient sInstance;

    private PicassoClient() {
    }

    public static PicassoClient getInstance() {
        synchronized (PicassoClient.class) {
            if (sInstance == null) {
                sInstance = new PicassoClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        Picasso.with(context).load(imgUrl).into(view);
    }
}

那么加载图片就变成了下面这样:

ImgLoaderClientFactory.getImageLoaderClient(ImgLoaderClientFactory.UIL).load(mContext, imgUrl, imageView);

要切换图片框架呢?怎么办?全局搜索替换ImgLoaderClientFactory.UIL即可,比如想切到Glide,将用到ImgLoaderClientFactory.UIL地方改成ImgLoaderClientFactory.GLIDE即可。

ImgLoaderClientFactory.getImageLoaderClient(ImgLoaderClientFactory.GLIDE).load(mContext, imgUrl, imageView);

本文原创作者:MichaelX,博客地址:http://blog.csdn.net/xiong_it.转载请注明来源

欢迎光临:MichaelX’s Blog

总结

工厂方法适用于:隔离客户端与待使用的目标产品,用工厂来生产目标产品即可。

好了,今天的《设计模式Android篇:工厂方法模式》就到这里,请继续关注《Design Patterns in Android》(设计模式Android篇)系列博文,欢迎各位读者朋友评论区拍砖交流,共同进步。

猜你喜欢

转载自blog.csdn.net/Xiong_IT/article/details/54575488