阅读 253

设计模式实操经验浅析

参考资料

  1. Head First 设计模式(中文版)-- [美] 弗里曼(Freeman,E)

  2. 大话设计模式 - 程杰著

转载说明:掘金独家发布,禁止转载。 -- hlwang

综述:

本文汇总近些年架构设计中设计模式的心得体会。

在我看来,设计模式功法描述的是一个“人情淡薄”的世界:“对象间尽量不要有面对面往来,各自干好本职工作,最好不知道特定对象的存在”。

  • 策略模式:算法家族
  • 观察者模式:极度解耦,开闭原则经典案例之一。
  • 装饰者模式:俄罗斯套娃,开闭原则经典案例之一,想象一下,如果装饰对象被成千上万的业务使用,你一个新业务敢随便修改它的一行代码吗?
  • 工厂模式:面向抽象编程,依赖倒转
  • 命令模式:寄快递。你是命令发起者(寄快递),快递收件小哥是命令的接收者,物流货运具体执行运输。在这个场景中,你需要关心是具体那个快递小哥收件吗?不需要。快递小哥,需要关心快件是卡车运输还是飞机运输吗?明显也不需要。物流运输需要关心寄件人是谁吗?更不需要。想象一下,如果三方互相关心,你的程序还有迭代空间吗?
  • 适配器:孙悟空七十二变化妆成小妖精深入敌穴打探情报。
  • 模范方法。电商业务中,用户点击购买按钮的算法设计:是否登陆 --> 身份校验(能够购买) --> 下单。不同的电商子业务,身份校验可能也会不同。例如:金币兑换、新客业务等就需要校验不同的数据部分。
  • 迭代器模式:迭代器中有适配器的影子,适配器中有代理的影子,所以,你品吧。
  • 组合模式:整体与部分之歌
  • 状态模式:经典案例-秒杀的业务场景:可预约-->倒计时-->抢购中-->已抢光-->已结束,每一个节点都可以使用一个节点来封装。

一、策略模式

定义:

定义了算法家族,使它们可以互相替换,此模式让算法的变化独立于使用它的客户。

浅析:

  • 策略模式,与模范方法都跟算法相关,但前者使用“组合”,后者依靠“继承”。
  • 封装变化。面向算法编程,那么策略模式解决的就是一个“点”上的问题。算法大、全、包罗万象,就容易耦合,在变化时,就不易精准切割。
  • 面向接口/超类型编程,不要面向具体依赖

应用场景:

应用最广泛的设计模式。

  • RecyclerAdapter(适配器模式) 之于 RecyclerView(适配器客户),就是不同的策略。
  • Google 轻量级网络库-Volley,大量使用了策略模式
  • 理论上有 if/else 的地方,都可以使用策略模式。

二、观察者模式

定义

定义了对象间一对多的依赖,当一个对象发生状态改变时,依赖对象都能收到通知并自动更新。

浅析

  • 要与 发布-订阅模式 区分开,还是有些区别的
  • 解耦合。状态变化了,告诉我(观察者)一声,怎么处理,是我(观察者)的事
  • 要注意registerunRegister配对,注意内存泄漏。所以,还有个疑惑,“主题中的观察者池子一定要用强耦合吗?”

应用场景

  • RxJava。俄罗斯套娃式级联观察者,这套娃玩的真溜。
  • ContentProvider+Custor+CustorAdapter。级联的观察者,案例可以参考:Android源代码-短彩信-短信列表数据实现方式。

三、装饰者模式

定义

动态的将责任添加给对象,在扩展类功能上,装饰者相比继承提供了更加有弹性的方案。

浅析

  • 俄罗斯套娃。组合的方式,持有装饰的对象句柄。这里有一点需要额外注意,装饰者中并非没有继承,但装饰者并不是通过继承获得“行为”,而是为了获得一样的类型。
  • 类爆炸。继承会产生:“类爆炸”。装饰者模式的重点在最后一句:弹性
  • 同样是使用组合解决问题,注意和策略模式区分。
  • 开放-封闭原则。这个对初学者很难懂,听起来也很矛盾,想想装饰者,既扩展了原有对象的行为,又没有改变原对象一行代码。想象一下,如果装饰对象被成千上万的业务使用,你一个新业务敢随便修改它的一行代码吗?

应用场景

  • 经典案例:InputStream + BufferedInputStream/LineInputStream,做过IO的都懂。
  • 既然都说到俄罗斯套娃了,RxJava 也是其经典案例。RxJava中的每一个Operator都是其应用,动态的将责任附加给新对象。RxJava官网
  • View + ViewGroup + LinearLayout。

四、工厂

定义

简单工厂:与其说设计模式,不如说:编程习惯、约定。 工厂方法:定义了创建对象的方法,但由子类来决定实例化的对象是哪一个。此模式将对象的创建延迟到子类。 抽象工厂:定义了一个接口,用于创建对象相关或依赖的家族,但不用指定具体类。

浅析

  • 应用非常广泛的对象创建者模式。
  • 针对抽象编程。以工厂方法为例,定义了创建对象的方法,即:我们定义了一个对象抽象,创建的对象一定是其的子类型。对使用该模式的客户来说,它一点都不关心具体的对象类型。
  • 依赖倒转/依赖倒置。不能让高层组件依赖低层组件,两者都应该依赖于抽象。

应用场景

  • Adapter(RecyclerViewAdapter)。Adapter中会定义一系列的对象依赖家族,例如:count()、viewType()、ViewHolder()、getId()等等。想象一下,更换列表展示,只需要简单更换一个新的Adapter就完成了,是不是很方便?
  • Android源代码Framework Telephony模块。GsmPhone、CDMAPhone等不同通话协议,以Phone为接口,生产其相关或依赖的家族。

五、单例模式

定义

确保一个类只有一个对象,并提供全局访问点。

浅析

单例模式的七种写法

六、命令模式

定义

将请求封装成对象,以便使用不同的请求、队列、日志来参数化对象,此模式还可应用于撤销操作等场景。

浅析

  • 命令模式是分角色的分离,每个角色可以有自己的决策。
  • 寄快递。你是命令发起者(寄快递),快递收件小哥是命令的接收者,物流货运具体执行运输。在这个场景中,你需要关心是具体那个快递小哥收件吗?不需要。快递小哥,需要关心快件是卡车运输还是飞机运输吗?明显也不需要。物流运输需要关心寄件人是谁吗?更不需要。想象一下,如果三方互相关心,你的程序还有迭代空间吗?

应用场景

  • Android Handler+Msg。Handler在Android中特别常见,就不阐述了。

七、外观模式

定义

提供了一个统一的接口,用于访问子系统的一群接口。外观模式定义了一个高层接口,此模式让子系统更容易访问。

浅析

  • 外观模式让客户和子系统之间避免紧耦合。
  • 最小知识原则/迪比特法则。还记得文章开头的那句话吗?你知道子系统能帮你做什么就好了,尽量不要让主系统与子系统发生耦合。

应用场景

  • 三方组件提供的初始化 init 接口

八、适配器

定义

将一个类的接口,转换成客户希望的接口。此模式让互不兼容的接口类型合作无间。

浅析

  • 转换器。模式中有代理模式的影子,但模式的重点在于接口方法的转换,目的在于让程序更加兼容,减少程序编写复杂度。类似:孙悟空七十二变化妆成小妖精深入敌穴打探情报。

应用场景

  • Adapter。
  • 搭配装饰者使用。装饰者要求同样的超类型,适配器模式在此有一定的用武之地。

九、模板方法

定义

在一个方法内,定义了算法的骨架,将算法的一部分步骤延迟到子类。模板方法使得子类在不修改算法结构的情况下,重新定义算法中的某些步骤。

解析

  • 涉及到算法,又涉及到延迟到子类。是不会会想起来策略模式与工厂方法模式。
  • 使用继承解决问题。

应用场景

  • 生命周期方法
  • RecyclerAdapter。VH onCreateViewHolder + onBindViewHolder 都是需要子类重写的。
  • 电商业务中,用户点击购买按钮的算法设计:是否登陆 --> 身份校验(能够购买) --> 下单。不同的电商子业务场景,身份校验规则也是不同的。例如:金币兑换、新客业务等就需要校验不同的数据部分。

十、迭代器模式

定义

提供了一个方法,用于顺序访问集合中的各个元素数据,而又不暴漏其内部实现。

浅析

  • 迭代器中有适配器的影子,适配器中有代理的影子,所以,你品吧。
  • 迭代器的重点一是提供了一种顺序访问的方式;重点二:是不暴漏内部实现。

应用场景

  • 遍历访问场景
  • java.util.Iterator

十一、组合模式

定义

允许你的对象组合成树形的结构来表现“整体/部分”层次结构,以便以一致的方式处理个别对象以及对象组合。

浅析

  • 整体/部分。整体也是由部分组成,所以,可以使用一致的方式处理个别对象以及对象组合。

应用场景

  • 公司与分公司
  • 主菜单与子菜单

十二、状态模式

定义

允许对象在内部状态改变时,改变它的行为,对象好像改变了它的类。

浅析

  • 状态模式与策略模式类图一模一样,注意区分。主要的差异点在于“意图”。
  • 现象有一个时间轴,时间改变,推进状态切换,进而类对外提供的特性也就发生改变。

应用场景

  • 秒杀业务。秒杀的业务场景:可预约-->倒计时-->抢购中-->已抢光-->已结束,每一个节点都可以使用一个节点来封装。
  • Android源代码Framework - Wifi。WifiStateMachine,实现了Wifi的工作场景:扫描、连接、连接成功。

状态机框架组件

十三、代理模式与装饰者模式的区别?

Q:装饰模式和代理模式的UML基本就是相同的,区别具体在哪呢?

装饰器模式应当为所装饰的对象提供增强功能,而代理模式对所代理对象的使用施加控制,并不提供对象本身的增强功能。

使用方式上,代理模式一般在代理类中确定了要被代理的目标对象,客户端根本不知道被代理类的存在。而装饰模式中被装饰者对象需要客户端创建提供,并且可以层层嵌套,层层装饰。

十四、适配器模式跟代理模式的区别?

适配器模式跟代理模式乍一看也有点像?

适配器关联了适配者,代理关联了被代理者,它们都满足了合成复用原则(使用关联而不是继承)。但是他们确实也有很大的不同,比如适配器的作用是为了协调新旧接口,代理的作用是在客户端和被代理者之间帮忙做一些额外的事。

文章分类
阅读
文章标签