前言: 能在平时的coding中,使用到设计模式,是一件非常细节的事,但恰恰也是走向高阶的开端,同样一段代码,不同的人写,水平是不一样的。今天是由gdutxiaoxu投稿本公众号授权发布的,gdutxiaoxu之前写的《记一次360面试》也是在本公众号独家发布的,是老朋友了。gdutxiaoxu的blog:http://blog.csdn.net/gdutxiaoxu/. 看下正文:

写在前头,这篇博客对于老司机们没什么多大的意义,老司机们就不用看了,对于新手还是有很大实用价值的。

平时在项目中,你们有没有遇到这样的情况,比如之前项目是使用开源框架ImageLoader,现在想使用Picasso或者Glide,这时候你会怎么办呢?是一行一行代码去改吗?

当然可以,如果项目使用到ImageLoader相应的方法少的话,那还可以,但是一旦项目比较大型的话,这会是多大的工作量,估计至少得改个几天,累先不说,至少毫无意义,那怎么办呢?别急,下面就来讲解。

第一种方法

这种方法大多数人都会使用,直接封装成为一个工具类,提取公共参数,以后想修改的话,直接修改工具类里面具体的实现

public class ImageLoaderUtils {public static void loadImageView(Context mContext, String url, ImageView mImageView) {Picasso.with(mContext).load(url).into(mImageView);}
}

这个时候我们的项目中如果不想使用Picasso,这个时候我们想使用Glide,我们只需修改 ImageLoaderUtils类中方法的具体实现即可,代码如下

public class ImageLoaderUtils {/*** 指定大小加载图片** @param mContext   上下文* @param url       图片路径* @param mImageView 控件*/public static void loadImageView(Context mContext, String url, ImageView mImageView) {
//        Picasso.with(mContext).load(url).into(mImageView);Glide.with(mContext).load(url).into(mImageView);}
}

看了上面的代码,相信大多数人都知道,如果我们不封装,我们必须查找每个类文件里面使用到Picasso的相应方法的位置,然后再替换,这会是一个很大的工作量。而我们如果进行封装,只需更改工具类里面的方法的具体实现,这样是不是很方便呢?看到这里,你是不是觉得这篇文章结束呢,还没,下面介绍另外一种方法,这种方法将更加优雅。

那就是使用简单工厂模式。


简单工厂模式

定义

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。简单点说就是用来创建具有相同基类的对象

类UML图

角色介绍

从上面的UML图可以看到,总共有三个角色Factory,Product,ConcreteProuct,其中Factory依赖于Product

Product:产品的基类,通常有抽象类或者接口来充当,用来统一接口,不关心细节的实现

ConcreteProduct:Product的具体实现类

Factory:工厂类,用来创建对象,可以根据参数的不同返回不同的Product对象,实现逻辑封装在其内部

使用步骤

从上面的分析,我们知道,采用简单工厂模式,一般需要三个步骤

  • 抽象Product的共同特点,定义成一个接口或者抽象类

  • ConcreteProduct的具体实现

  • 实现Factory

下面我们一起来看一下怎样运用于替换图片框架上


简单工厂模式的运用——几行代码更换图片框架

首先为了加深理解,我们一起先来看一下类UML图

接着按照上面的三部曲,第一步,我们先定义一个接口IimageListener,用来统一参数

public interface IimageListener {void display(Context context, ImageView imageView, String url, int progressId, int errorId,Object tag);void display(Context context, ImageView imageView, String url, int progressId, int errorId);void display(Context context, ImageView imageView, String url, int progressId);void display(Context context, ImageView imageView, String url);void display(Context context, ImageView imageView, Uri uri);
}

第二步,我们来写GlideRequest和PicassoRequest的具体实现

public class GlideRequest implements IimageListener {@Overridepublic void display(Context context, ImageView imageView, String url, int progressId, interrorId, Object tag) {DrawableTypeRequest<String> load = Glide.with(context).load(url);if (progressId != -1) {load.placeholder(progressId).centerCrop();} else {load.placeholder(new ColorDrawable(Color.GRAY));}if (errorId != -1) {load.error(errorId);}else{load.error(R.drawable.ic_error);}load.into(imageView);}@Overridepublic void display(Context context, ImageView imageView, String url, int progressId, interrorId) {display(context, imageView, url, progressId, errorId, null);}@Overridepublic void display(Context context, ImageView imageView, String url, int progressId) {display(context, imageView, url, progressId, -1, null);}@Overridepublic void display(Context context, ImageView imageView, String url) {display(context, imageView, url, -1, -1, null);}@Overridepublic void display(Context context, ImageView imageView, Uri uri) {DrawableTypeRequest<Uri> load = Glide.with(context).load(uri);load.into(imageView);}
}

PicassoRequest

public class PicassoRequest implements IimageListener {@Overridepublic void display(Context context, ImageView imageView, String url, int progressId, interrorId, Object tag) {Picasso.with(context).load(url).placeholder(progressId).error(errorId).tag(tag).into(imageView);}@Overridepublic void display(Context context, ImageView imageView, String url, int progressId, interrorId) {Picasso.with(context).load(url).placeholder(progressId).error(errorId).into(imageView);}@Overridepublic void display(Context context, ImageView imageView, String url, int progressId) {Picasso.with(context).load(url).placeholder(progressId).into(imageView);}@Overridepublic void display(Context context, ImageView imageView, String url) {Picasso.with(context).load(url).into(imageView);}@Overridepublic void display(Context context, ImageView imageView, Uri uri) {Picasso.with(context).load(uri).into(imageView);}
}

第三步,我们来写工厂类ImageRequestManager的实现,可以看到我们可以根据不同的参数返回不同的实例,进而来决定使用Picasso或者是Glide

public class ImageRequestManager {public static final String type_Glide="Glide";public static final String type_Picasso="Picasso";public static final String type_default =type_Glide;private ImageRequestManager(){}public static IimageListener getRequest(){return getRequest(type_default);}public static IimageListener getRequest(String type){switch (type){case type_Glide:return new GlideRequest();case type_Picasso:return new PicassoRequest();default:return new GlideRequest();}}
}

最后,以后我们想加载图片只需简单调用下面的方法就OK了,简单明了,再也不用怕替换框架了

ImageRequestManager.getRequest().display(mContext, imageView, imageUrl);

讨论

情景一:之前我是使用Glide框架,现在想使用Picasso框架,那要怎么办呢?

只需将 ImageRequestManager 里面的 String typedefault=typeGlide 更改为String typedefault=typePicasso 就ok了。

//public static final String type_default =type_Glide;
public static final String type_default =type_Picasso;

情景二:有人会说了,平时在项目中基本只会使用一种图片加载框架,要么使用Picasso,要么使用Glide,你这样做同时使用了两种框架,无疑增加了APK的大小,那要怎么办呢?其实很简单

如果你只想使用Picasso,去掉Glide的具体实现就OK了,同理你只想使用Glide,去掉Picasso的具体实现就好了,不过建议保留空方法,以后要修改就不必更改工厂类 ImageRequestManager 里面的逻辑呢


简单工厂模式总结

  • 将对象的创建工作与对象的业务逻辑分析,降低了系统的耦合度

  • 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。为了调用者的方便,我们可以给工厂类添加一个默认参数,这样调用的时候不必每次传入参数

  • 从上面知道的例子,我们知道,业务逻辑大部分在工厂类里面,如果工厂类需要创建的对象不多的话,简单工厂方法模式还是很有很大的优势的,而如果需要创建很多对象的话,那工厂里面无疑要增加很多case 语句,这样会导致工厂类的职责太重了,破坏了类的单一性。

综上所述:

简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。

简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。


扩展

看了上面的文章,对于于Volley,OKhttp等网络框架的简单封装,你是不是也想到了什么,应该懂得怎么封装了吧。

而对于Retrofit的封装,你有没有想到了什么呢?因为Retrofit的返回对象比较特殊,是 Observable<>,更其他的网络框架不太一样,其实还是可以大概处理一下的,这里暂时就不讨论了,大家有兴趣的可以自己先去尝试,相信你会收获到很多东西的。


题外话

万丈高楼平地起,对于程序猿的我们,一定要多动手实践,我相信很多同学看到这里,都基本掌握了,但是很有很多同学不动手去实践一下,就这样,几天过去了,似懂非懂,最后忘记了,而这恰恰是分水岭。哈哈,就扯蛋这么多了。


最后给出github地址,上面的小项目是我平时没事写写玩玩的。

github地址: https://github.com/gdutxiaoxu/FunAPP

相关阅读:记一次360面试总结(Android)也是gdutxiaoxu写的。

第一时间获得博客更新提醒,以及更多android、小程序干货,源码分析,最新开源项目推荐,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

使用第三方框架解耦的一种思路—简单工厂模式的运用相关推荐

  1. 工厂方法模式的一种特例——简单工厂模式

    工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory) 这三种模式从上到下逐步 ...

  2. Java23种设计模式之工厂模式

    工厂模式 前言 一.简单工厂模式 二.工厂方法模式 优点: 缺点: 三.工厂方法模式适合应用场景 总结 前言 核心本质: 1.实例化对象不使用new,用工厂方法代替, 2.将选择实现类,创建对象统一管 ...

  3. 23种设计模式之简单工厂模式,工厂方法模式,抽象工厂模式详解

    工厂模式详解 1. 简单工厂模式 1.1 需求分析 1.2 使用传统方式实现 1.2.1 类图 1.2.2 代码实现 1.2.2.1 新建pizza抽象类 1.2.2.2 希腊披萨实现类 1.2.2. ...

  4. 浅谈Spring框架应用的设计模式(一)——工厂模式

    文章目录 前言 一.工厂模式介绍 1.简单工厂模式 (1)静态工厂模式 (2)利用反射机制实现的简单工厂 2.工厂方法模式 3.抽象工厂模式 二.Spring框架中工厂模式的重要应用 1.BeanFa ...

  5. 二次封装图片第三方框架——简单工厂模式的运用

    CSDN首发地址: 前言 写在前头,这篇博客对于老司机们没什么多大的意义,老司机们就不用看了,对于新手还是有很大实用价值的. 平时在项目中,你们有没有遇到这样的情况,比如之前项目是使用开源框架Imag ...

  6. 一种思路:策略模式 + 反射工厂,很好的实现了开闭原则

    作者 | 麻辣你个王子 来源 | blog.csdn.net/qq_28675967/article/details/90581208 应用场景:某天接到了一个需求,品牌给了一个第三方接口,例如:ww ...

  7. Java使用简单工厂模式对面向接口编程模式的深度解耦实现

    在Java和C#的编程世界里,并没有出现像C++那样的多脉继承,它们只支持单一的继承,或者多级继承,这一变化最大的影响,我觉得是大大的降低了编程的难度,因为没有了C++的多级多脉继承,所以接口出现了, ...

  8. 研磨23种大话设计模式------简单工厂模式 + 工厂方法模式 + 抽象工厂模式

    大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正 如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer 简 ...

  9. 23种设计模式之工厂模式学习笔记

    什么是工厂模式? 工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式.该模式用于封装和管理对象的创建,是一种创 ...

  10. 23种设计模式 -----Day01:简单工厂模式

    目录 前言 1.设计模式(Design pattern)定义 2.为什么要使用设计模式(使用设计模式的意义) 3.设计原则 a.单一职责原则 b.开放封闭原则 c.里氏代换原则 d.迪米特法则 e.依 ...

最新文章

  1. android hal 驱动,AndroidHAL-Teseo
  2. gitlab安装_Gitlab安装和配置教程(包括邮箱配置)
  3. 中继技术助威 Wi-Fi网路涵盖范围三级跳
  4. main()与_tmain()区别
  5. 从零学习SwinTransformer
  6. JVM的内存区域划分(转)
  7. mysql 查询语句性能优化
  8. python - easy_install的安装和使用
  9. 数据结构排序系列详解之五 简单选择排序
  10. 胡明浩 160809313 (我就会三个)
  11. cpu核心分配给不同进程linux,Linux技巧:多核下绑定硬件/进程到不同CPU
  12. 微信小程序自定义导航栏样式
  13. 标准盒模型与怪异盒模型的区别
  14. Java坑人面试题系列: 包装类(中级难度)
  15. 阿里云推出网盘App,开放申请!非会员下载 10MB/s! 还有更厉害的:60M/s
  16. 22春天津大学《国际金融学》在线作业二
  17. OLAP引擎调研 —— OLAP引擎性能对比分析
  18. ffmpeg与ffdshow的关系
  19. ffmpeg断流黑屏问题分析
  20. bootstrap-table 一直显示“正在努力地加载数据中,请稍候”的问题

热门文章

  1. 线下广告投放方案_本地餐饮该怎样做好广告投放?传统广告投放的弊端和痛点...
  2. Java使用apache commons连接ftp修改ftp文件名失败原因
  3. 电脑基本快捷键,你知道多少?
  4. Tensorflow训练渐渐变慢,迭代一段时间卡死
  5. 删数问题(Noip1994)
  6. 帝国CMS-后台管理工具
  7. python之列表相关操作
  8. [原创]linux简单之美(三)
  9. Kinect 深度测量原理
  10. 云计算时代的数据库研究