简记Android源码设计模式——第二篇

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

本文章为读《Android源码设计模式》后简记,简记总结,部分内容摘抄自该书,推荐读者可阅读这本书,的确很不错。

享元模式

介绍

享元模式也是用的比较多的一个模式。其目的是达到部分状态可共享,可共享的状态为内部状态(不随外部环境改变),不可共享为外部状态(可随外部环境改变)。原理即是做缓存对象处理。

比如Android中的Message,推荐使用handler的obtain方法来获取一个message,这种方式获取的message是从message池里获取出来使用的,当使用完成之后,又recycle放回message池里,默认池大小为50,回收的时候,如果池里小于50个则放入池中,使用时从中取出,Message是使用链表方式存储。

UML

使用场景

  • 存在大量相似对象
  • 细粒度对象有接近的外部状态,且内部状态与环境无关。
  • 需要缓冲池的场景

备忘录模式

介绍

此模式是行为模式之一。上一个我们说到了享元模式,使用缓存的原理,使得相似的对象可以复用从而达到可少创建对象的作用。而备忘录模式也是使用缓存,不过不是运行时缓存来减少对象创建,而是另一种目的,是想在外部保存对象的内部状态,使其下一次进入可以使用保存信息来恢复对象的状态。类似于玩游戏保存关数和已打出的隐藏人物可下次进入继续闯关和已出隐藏人物使用。

Android中的Activity和Fragment状态保存则是使用了该模式。通过onSaveInstanceState和onRestoreInstanceState来实现。
说下调用时机:

  • 用户按下Home
  • 长按Home,选择其他app时候
  • 按下电源键(关闭屏幕显示的时候)
  • 从Activity启动另外一个Activity的时候
  • 屏幕方向切换时候
  • 电话打入等情况

一句话概括:系统未经你许可,销毁你Activity,那么就会执行。

UML

  • Originator :代表源头,需要被存储状态的对象。对应我们的Activity和Fragment等
  • Memoto :备忘录对象,存储状态信息。单独用一个对象来存储,防止外部直接访问Originator。对应控件信息等
  • Careaker : 负责管理对象,用于控制存储备忘录和从备忘录获取存储信息。对应于存储状态信息的
    mActivitys里的ActivityClientRecord对象state中。

使用场景

  • 需要保存一个对象在某一时刻的状态或者部分状态
  • 一个对象不希望被外部直接访问其状态,则可以提供一个中间对象间接被访问,即提供一个Memoto

模版模式

介绍

重构必备,抽取基类,应对变化。书中说到,确定步骤执行顺序,但是某些步骤的具体实现是未知的,或者说实现是会随着环境变化而改变的。这里很明确了,例如,简单吃饭步骤。端起饭碗->夹菜->吃。在夹菜这个步骤就可能变化了,有的是夹肉,有的夹素菜。但端碗和吃是固定的,就可以抽取到基类中,而夹菜这个步骤可以抽象让子类去实现。

该模式的定义为,定义操作框架,将某些步骤延迟到子类中,使得子类可以不改变算法结构情况下即可重定义算法的某些特定步骤。

在Android中AsyncTask中的回调,还有咱们Activity的生命周期都是模版模式的体现。

UML

使用场景

  • 多个子类有公有方法,并且逻辑基本相同的时候。(重构场景)
  • 重要,复杂的算法,可以把核心算法设计为模版方法,周边相关细节由子类实现

外观模式

介绍

外观模式,提供一个统一的接口供使用者访问,隐蔽内部实现,制作API必备。应该每一个开发者都会使用到,因为你在使用SDK的时候受到的熏陶,无意之间自己写也经常会封装。只是可能你并没有把它认识为到模式层面。

Android中,Context就用到来外观模式,像什么startActivity()、sendBroadcast()等等,就是该类提供出来的外观方法。

UML

  • Faced : 外观接口,通过该类提供的方法来间接访问子系统
  • SysyemA-C: 子系统,涵盖被调用的具体实现

使用场景

  • 需要为提供一些子系统提供一个统一接口供外部访问的时候。可以隐藏内部细节,后续不断演化越来越复杂,可以隔离变化。制作APi时候
  • 需要构建层次结构的子系统时候,使用Faced定义每个层次人口。如果子系统相互依赖,通过Faced接口进行进行通信,从而简化它们之间依赖(后面这句话同时也代表着中介者模式的场景)

中介者模式

介绍

对于中介者模式,就一句话,将多对多改变为一对多,也就由网状对结构改为了星型结构。子系统相互依赖的时候,通过中介者来调用依赖方,这样子系统就不必知道另外的子系统,所有子系统都只知道中介者。而中介者知道所有子系统。

Android中,Keyguard锁屏就是中介者模式的体现,KeyguardViewMediator类中含有AlarmManager、AudioManager、StatusBarManager、PowerManager···,像XXXManager这些就是同事类,都由KeyguardViewMediator来调节。

UML

  • AbsSystem :抽象系统,持有中介者引用
  • ConcreteSysteA,ConcreteSysteB:具体子系统
  • ConcreteMediator :具体中介者,可操作各个子系统

使用场景

  • 对象之间操作很多,又依赖复杂时候,可以通过中介者将多对多改为一对多方式的时候

装饰模式

介绍

结构型模式之一,通过装饰者持有组件(被装饰者)的引用,也含有调用组件的方法。而这两个往往两个都是抽象,都有具体的实现。那么在具体的装饰者中,调用具体的组件方法,使用super方式来调用,再其调用前后可以自由添加想用的新增方法,这新增方法就是装饰了。

Android中咱们常用的startActivity()等方法,是在Context中,而具体实现是ContextImpl,然而持有ContextImpl的是Activity继承对象ContextWrapper。这也是装饰者模式的体现。

UML

  • Component : 抽象组件,被装饰者
  • ConcreteComponent : 具体组件
  • Decorator : 装饰者,其内部有一个指向被装饰者的引用,大多数情况该类抽象,如果逻辑单一,可以直接处理为具体装饰者。
  • ConcreteDecortorA、ConcreteDecortorB : 具体装饰者

使用场景

  • 需要透明且动态扩展该类的功能时

桥接模式

介绍

结构型模式之一,顾名思义,目的为连接两边。这里的两边可以指的是两个独立变化的方向,如电器和开关,开关很多种,电器很多种,两者独立变化又是耦合。通过桥接模式,可将多维度变化类或者多个树状类之间的耦合解耦。

Android中view视图层级,控件与绘制到屏幕相关实现类DisplayList、HardWareLayer和Canvas可以看作桥接模式。Adapter和AdapteView也可以看作桥接模式。Window和WindoeManager之间也可以看作桥接模式,Window为抽象部分,PhoneWindow为具体实现扩展,而WindowManager为实现部分的基类,WindowManagerImpl为具体逻辑实现,通过使用WindowManagerGlobal通过IWindowManager接口与WMS进行交互,由WMS完成具体的窗口管理工作。

UML

  • Abstraction : 抽象部分,保持一个对实现部分对引用,需要调用实现部分的对象来实现。
  • RefineAbstraction : 具体抽象部分,一般是抽象部分方法进行完善。
  • Implementor : 实现部分,可以接口可以抽象类,一般提供基本操作,由抽象部分业务方法中来调用。
  • ConcreteImplementorA、ConcreteImplementorB : 具体实现,完善实现逻辑。

其实看了UML图后,你就会发现和前一个讲到的装饰者模式挺像的。

使用场景

  • 多维度变化或者多个树状图之间的耦合需要解偶时
  • 避免两个层次之间建立静态的继承关系,通过桥梁模式在抽象层建立关联关系
  • 不希望使用继承或者多层继承导致系统类的个数急剧增加的系统

适配器模式

介绍

顾名思义,就是要做到适配的作用,类似于电源适配器,转换进电达到出电固定。将两个不兼容电融合到一起,粘合剂到作用。书中提到,把一个类到接口变换成客户端所期待到另一种接口,从而使得原本接口不匹配无法在一起工作到两个类能够在一起工作。

Android中到ListView、GridView、RecycleView都需要使用到的Adpater则使用到了适配器模式。ListView使用的Adapter缓存的View,在getView中无论如何定义布局,返回的都是View。RecycleView的Adapter中缓存的ViewHolder,在onCreateViewHolder中返回。

UML

类适配器

  • Target : 目标角色,期待得到的接口。类适配器,该目标不可以是类
  • Adaptee : 源接口,需要被转换适配的接口
  • Adapter : 适配器角色,把源接口转换成目标接口。这一角色不可以是接口,是具体类。

对象适配器

对象适配器,使用代理关系连接到Adaptee类。通过适配器类来衔接。

使用场景

  • 需要使用现有的类,但是接口不符合系统要求,需要转换一下
  • 想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类。包括一些可能在将类引进的类一起工作
  • 需要一个统一的输出接口,输入端的类型不可预知

迭代器模式

介绍

又成为游标模式,行为型设计模式之一。我的理解是目的在遍历,弱化容器与遍历算法的关系。在容器与访问类中添加一个迭代器,用于承担遍历,又不需要访问类自行实现。提供一种方法顺序访问一个容器对象中的各个元素,又不需要暴露该对象的内部表示。

Android中数据库cusor则使用到了该模式。各个语言一般都又各自的迭代器实现,很少会自己去实现迭代器了。

UML

  • Iterator : 迭代器接口。负责定义、访问和遍历元素的接口
  • ConcreteIterator : 具体迭代器类。实现迭代器接口,并记录遍历的当前位置
  • Aggregate : 容器接口。负责提供创建具体迭代器的接口
  • ConcreteAggregate : 具体容器类。

使用场景

  • 遍历一个容器对象时

命令模式

介绍

行为型设计模式之一。这个模式没有规矩,比较灵活。将一些列的方法调用封装,用户只需要调用一个方法执行,那么所有这些被封装的方法就会被挨个执行调用。如名字一样,命令,比如开机命令,只需要一条命令,内部操作都封装好了自己执行。很多时候封装API其实也可以看作是一个简单的命令

Android中使用多,但不是很典型,比较典型的是Android的时间机制中底层逻辑对事件的转发处理,Android的每一种事件在屏幕上产生后都会经由底层逻辑将其转化为一个NotifyAgs对象,NotifyAgs相当于一个命令者抽象。InputDispatcher则为请求者,接受者角色由硬件驱动承担

UML

  • Receiver:接受者角色,负责具体实施或执行一个请求,执行具体逻辑的角色
  • Command:命令角色,定义所有具体命令类的抽象接口
  • ConcreteCommand: 具体命令角色,相当于一个中间角色,调用接受者的相关方法,在接受者和命令执行的具体行为之间加以弱耦合
  • Invoker: 请求者角色,该类职责就是调用命令对象执行具体的请求,相关方法称为行动方法
  • Client: 客户端角色

使用场景

  • 需要抽象待执行操作,以参数形式提供出来——类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品
  • 在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始化请求无关的生存期
  • 需要支持取消操作
  • 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍
  • 需要支持事务操作

解释器模式

介绍

行为型模式,不过该模式用的很少。说实话看起来也很难懂。在于自己定义构建一个解释器来解释一种文法并执行。

Android中PackageParser对咱们对Manifest的解析就可以看作解释器的实现。Activity、Service、Provider、Permission等构件在内部以内部类的方式创建了对应的类,按照解释器的定义,这些类在AndroidManifest.xml中都对应一个标签,这就是文法,其在对该配置文件解析的时候充分利用了解释器模式分离实现与解释执行的特性

UML

  • AbstractExpression:抽象表达式,声明抽象的解释操作父类,定义一个抽象的解释方法,具体实现在各个子类完成
  • TerminalExpression:终结符表达式(叶子),实现文法中与终结符有关的解释器操作,文法中每一个终结符都有一个具体的终结表达式与之对应。
  • NonterminalExpression: 非终结符表达式(枝干),实现文法中与非终结符有关的解释操作
  • Context:上下文相关类,包含解释器之外的全局信息
  • Client: 客户端类,解析表达式,构件抽象语法树,执行具体的解释操作等

使用场景

  • 某个简单的语言需要解释执行且可以将该语言中的语句表示为一个抽象语法树时
  • 某些特定领域出现不断重复的问题时候,可以归纳转化为一种语法规则,然后构建解释器来解释该语句

组合模式

介绍

本模式为结构型设计模式之一,也称为部分与整体模式。在上面说到解释器模式,里面有叶子和枝干到概念。本模式也有叶子和枝干到概念。将一组相似到对象看作一个对象处理,并根据一个树状架构来组合对象,提供一个统一的方法去访问相应的对象。总公司又子公司和其部门组成,子公司又有自己的部门,这里母公司就是根,母公司部门就是叶子,子公司就是枝干,子公司部门又是叶子。

将对象组合成树形结构,使得单个对象和组合对象的使用具有一致性

像我们文件和目录使用的则是组合模式。Android中View和ViewGroup则也是使用的组合模式。组合模式这里谈到了两个概念:
* 透明模式: 组合使用的方法都定义在抽象类
* 安全模式: 组合使用的方法定义在自己内部

UML

透明模式

安全模式

  • Component : 抽象根节点,为组合对象中的对象声明接口。在适当情况下可实现所有公共接口行为,用于访问和管理Component字节点,可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它
  • Composite: 定义字节点的那些枝干节点行为,在组合中定义对象的行为与字节点有关的操作
  • Leaf: 在组合中代表叶子节点对象,叶子节点没有子节点
  • Client: 通过Component直接操作对象

安全模式中,由于枝干部分行为定义在枝干中,那么只有直接使用枝干来操作,这样违背了依赖导致原则,所有有了透明模式。透明模式是都用抽象对象来操作了,但是叶子节点多了自己不需要的方法。看情况自己指定

使用场景

  • 表示对象-部分整体层次结构时
  • 从一个整体中能够独立出部分模块或功能的场景

访问者模式

介绍

访问模式是23种模式中最复杂的一个。目的在于将数据操作与数据结构进行分离。一个系统由许多对象组成,每个对象都有一个accept操作来接收访问者访问,对象会调用访问者的visit方法传入该对象,使得访问者可以访问处理对象结构中的每个元素。访问者是一个接口,又根据实现不同的访问者来达到对系统类的不同访问实现。

Android中APT(Annotation Processing Tools)则是使用到了该模式,编译的时候编译器检查AbstractProcessor的子类,并且调用该类的process函数,然后将添加注解的元素都传递到process函数中,使得开发人员可以在编译器进行相应处理,例如根据注解生成新的java类,也是我们常用到的ButterKnife的基本原理

UML

  • Visitor: 接口或者抽象类,定义了对每一个元素访问对行为,参数就是可以访问的元素,方法个数理论上与元素个数是一样的,所以访问者模式要求元素的类族要稳定,如果要经常添加、移除那么说明不适合用这个模式
  • ConcreteVisitor: 具体访问者,需要给出每一个元素类访问的具体行为
  • Element:元素接口或者抽象类,定义接收访问者(accept)方法
  • ElementA、ElementB:具体元素类,提供接收访问方法的具体实现,通常是使用访问者提供的访问该元素类的方法
  • ObjectStructure: 定义当中所提到的对象结构,对象结构是一种描述,内部管理元素集合,并且可迭代这些元素集合供访问者访问。

使用场景

  • 对象结构比较稳定,但经常需要在此对象结构上定义新的操作
  • 需要对一个对象中的结构进行不同的操作(访问),而需要避免这些操作污染这些类,也不希望在增加新操作时修改这些类

猜你喜欢

转载自blog.csdn.net/ddxxii/article/details/78797467
今日推荐