结构型模式中的适配器模式、外观模式、装饰模式、代理模式都属于包装模式,都是对另外的类或对象的包装,只是各自的意图不同。

适配器模式通过对另外的类或对象的包装,将其接口转换为用户期望的接口,达到接口适配的目的。

外观模式是对包装的一组类或对象提供一个高层接口,意图是简化接口,使系统更加容易使用。

装饰模式的意图是在不改变包装对象接口的情况下为其增加另外的功能或职责。

代理模式的意图是通过对包装对象的包装以便控制对包装对象的访问。

适配器模式、外观模式对客户提供的接口与其包装类的接口有所不同,也就是这两种模式对客户来说改变了包装类的访问接口。而装饰模式、代理模式对外不改变所包装类的接口,对客户提供的接口与包装类的接口相同。

1、适配器模式

适配器模式包括两种:类适配器模式和对象适配器模式,一种使用了继承方式,一种使用了对象组合方式,相关的UML类图如下:

Android系统中适配器模式大量采用,由于ANDROID采用的是JAVA语言,而JAVA语言不支持多继承,因此在系统中采用的适配器模式主要是第二种,用来把包装对象的接口转换为需要的接口。

在Android系统中最常用的采用适配器模式的类为继承于BaseAdapter的类,如ArrayAdapter、CursorAdapter等,用来在底层数据和AdapterView视图之间提供适配,把对底层数据的读取接口转换为视图需要的接口。类图如下:

继承于AdapterView的视图(Client)通过Adapter(Target)的接口函数获得视图需要的数据,如Adapter接口函数getItem(int
position)从底层数据集获得位置position的数据项,getCount()函数获得数据集中的数据项的个数。

Adapter的具体类完成与不同底层数据类型读取接口的适配,如CursorAdapter类通过Cursor对象读取底层数据库中的数据,ArrayAdapter用来读取任意类型列表数组中的数据,HistoryAdapter用来读取类型为HistoryEntry的向量中的数据。

其它采用适配器模式的还有显示服务中DisplayAdapter类以及打印服务中的PrintDocumentAdapter类。DisplayAdapter用来适配不同类型的显示设备,用来侦测和发现系统连接的不同类型的设备。PrintDocumentAdapter用来适配不同的打印输出目标设备,如打印机或者文件,用来在这些设备输出打印内容。

2 、外观模式

外观模式的类图如下:

在Android 系统中使用的外观模式的地方比较多,可以说每个系统服务都对客户提供了一个访问该系统服务的管理门户类,用来方便访问对应的系统服务,如窗口管理服务对应的WindowManager,输入管理服务对应的InputManager,活动管理服务对应的ActivityManager等等。

另外ContentResolver、Log、Context、ServiceManager也可以看作门户模式的采用。

ContentResolver用来为应用提供访问数据模式的公共接口,Log为应用提供使用log输出系统的公共接口,Context为应用提供访问整个系统的接口。ServiceManager提供访问其它系统服务的入口。

3 、装饰模式

装饰模式的类图如下:

在Android系统中也有不少使用装饰模式的例子。如ContextThemeWrapper类及其派生类Activity和Service。UML类图如下:

ContextWrapper是对ContextImpl类的包装,Service类和Activity类都是ContextWrapper的派生类,Service类直接派生自ContextWrapper,Activity间接派生自ContextWrapper的子类ContextThemeWrapper,Service类和Activity类分别在ContextWrapper和ContextThemeWrapper类的接口基础上添加和实现了各自的生命周期回调接口(钩子),Activity类还提供了与其相关的窗口和视图显示相关的功能。ContextThemeWrappe的功能是在ContextWrapper基础上添加了对主题(Theme)的支持及在通过getSystemService接口返回服务管理对象时对于LAYOUT_INFLATER_SERVICE服务做了特殊处理,采用原形模式返回一个LayoutInflater对象的克隆对象。

4 、代理模式

      代理模式的类图如下:

在Android系统中代理模式也是普遍采用,每一个系统服务和本地服务都对应一个远端代理类,用来实现跨进程的访问系统服务或本地服务。每一个系统服务为一个Stub对象,而客户端通过一个Proxy对象访问对应的Stub对象。如管理管理服务对应的类图如下:

WindowManagerGlobal作为客户通过继承于接口IWindowManager的一个代理对象IWindowManager.Stub.Proxy跨进程访问系统服务WindowManagerService。

5  、桥接模式

桥接模式的意图为:将抽象部分与它的实现部分分离,使它们都可以独立地变化。这里的抽象和实现指的不是类的抽象和实现,而可以理解为功能抽象(或界面)和功能实现。任何具有实现关系的两个独立演化派生的类之间都可以构成桥接模式,桥接模式主要用在需要跨越多个平台的图形和窗口系统上。如所有介绍桥接模式的书中几乎都是以不同特性的窗口与窗口功能的实现,不同的视图(或图形)与视图(或图形)的绘制作为采用桥接模式的例子。如下为桥接模式的类图结构:

同样在ANDROID系统中不同的视图构成的视图树与完成视图的绘制功能的类之间,以及窗口类与窗口的功能实现类之间也可以认为采用的是桥接模式。相关类图如下:

图中不同的视图如Button、ImageView、TextView构成了一个抽象派生层次视图树,在视图树中View是所有视图的根视图,View的绘制通过三个不同的能独立演化的类来实现:Canvas(提供绘制表面)、HardwareLayer(提供输出显示层)、DisplayList(代表一个绘制操作)。

如下为ANDROID系统中窗口与窗口实现类之间的类图。Window、PhoneWindow构成窗口的抽象部分,Window是抽象部分的抽象接口,Window目前只提供了一个具体类PhoneWindow,Window的实现部分相关的类也构成了一个派生类图,WindowManager为窗口实现部分的基类,WindowManagerImpl为WindowManager的具体类,WindowManagerImpl通过WindowManagerGlobal并通过IWindowManager接口与窗口管理服务WindowManagerService交互,由窗口管理服务完成实际的窗口管理功能。

桥接与适配器两个模式非常类似,只是使用场合和观察角度不同。

在GOF所著的设计模式经典著作中对桥接模式与适配器模式的区别描述为:B r i d g e模式的结构与对象适配器类似,两个模式的不同之处主要在于它们各自的用途和出发点:B r
i d g e目的是将接口部分和实现部分分离和桥接,从而对它们可以较为容易也相对独立的加以改变和演化,B r i d g e模式能够为用户提供一个稳定的抽象和其实现接口。而A d a p t e r模式通过改变一个已有对象的接口,用来解决两个已有接口之间的不匹配,帮助实现不兼容的类之间协同工作,A
d a p t e r模式不考虑这些接口是怎样实现的,也不对其重新设计,也不考虑它们各自可能会如何演化。因此A d a p t e r通常在系统设计完成后使用,而B r i d g e模式必须事先知道一个抽象将有多个实现部分,因此在系统开始时就被使用。

因此从上面的描述可以看出:对一个采用桥接或适配器模式的已经完成的代码,从不同的观察角度可以看作桥接模式,也可以看作适配器模式。

6 、组合模式

组合模式的意图为:将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e使得用户对单个对象和组合对象的使用具有一致性。如下为类图结构:

采用组合模式的标准例子为图形、视图、菜单和窗口等,集合类(如数组)、文件目录也可以看作采用了组合模式。如下为ANDROID系统中采用组合模式的组合视图类图:

7 、享元模式

享元模式的意图为运用共享技术有效地支持大量细粒度的对象,类图结构如下:

享元模式也是普遍采用的模式。

在ANDROID系统中,每个应用组件都可以使用系统提供的众多服务管理对象,如WallpaperManager、AccessibilityManager、CaptioningManager、AccountManager等等。因此为了在一个组件内共享这些对象,在应用组件的Context的实现ContextImpl中,在ContextImpl类第一次加载引用时为每个管理对象都创建了一个ServiceFetcher对象(采用静态代码块),并根据服务名字把新创建的ServiceFetcher对象放到MAP集合中,每个ServiceFetcher对象在登记到MAP集合中时都分配了一个索引。

应用组件在调用Context.getSystemService来获得系统服务管理对象时,首先根据服务名字从MAP集合中获得对应的ServiceFetcher对象,然后调用ServiceFetcher对象的getService函数获得ServiceFetcher对象创建的服务管理对象。

在ServiceFetcher对象的getService函数中首先从Context维护的Cache数组列表中根据ServiceFetcher对象的索引查找是否已经包含有ServiceFetcher对象创建的服务管理对象,如果在Cache中存在服务管理对象,则直接返回Cache中保存的服务管理对象,否则调用ServiceFetcher的createService函数创建一个服务管理对象,并根据其索引放置到Cache中,以便下次使用。

版权所有,请转载时清楚注明出处和链接,谢谢!




ANDROID 中设计模式的采用--结构型模式的更多相关文章

  1. NET设计模式 第二部分 结构性模式(14):结构型模式专题总结

    ——探索设计模式系列之十五 Terrylee,2006年5月 摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能( ...

  2. 设计模式学习之外观模式(Facade,结构型模式)(8)

    1.什么是外观模式为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 2.为什么要使用外观模式在软件开发系统中,客户程序经常会与复杂系统的内 ...

  3. GoF的23种设计模式之结构型模式的特点和分类

    结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦合度低,满足 ...

  4. 结构型模式概述(Structural Pattern)

    结构型模式可以描述两种不同的东西:类与类的实例.结构型模式可以分为类结构型模式和对象结构型模式. 类结构型模式关心类的组合,可以由多个类组合成一个更大的系统,在类结构型模式中只存在继承关系和实现关系: ...

  5. ANDROID 中设计模式的採用--结构型模式

            结构型模式中的适配器模式.外观模式.装饰模式.代理模式都属于包装模式,都是对另外的类或对象的包装,仅仅是各自的意图不同. 适配器模式通过对另外的类或对象的包装,将其接口转换为用户期 ...

  6. Java设计模式之结构型模式

    结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 一.适配器模式: 意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接 ...

  7. 第27章 结构型模式大PK

    27.1 代理模式 VS 装饰模式 27.1.1 代理模式 (1)场景:客人找运动员代理要求安排运动员参加比赛 (2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些 ...

  8. 设计模式之美:Structural Patterns(结构型模式)

    结构型模式涉及到如何组合类和对象以获得更大的结构. 结构型类模式采用继承机制来组合接口实现. 结构型对象模式不是对接口和实现进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法. 因为 ...

  9. .NET设计模式(15):结构型模式专题总结(转)

    摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式).这些结构型模式,它们在某些方面具有很大的相似 ...

随机推荐

  1. DOS界面下的翻译软件制作

    准备 素材 依赖 接口 地址 参数 返回值解析 编码及测试 功能代码 运行脚本 环境变量 结果展示 英语转汉语 汉语转英语 总结 昨天看到一篇关于Linux下的桌面词典的文章,于是就想实现一个Wind ...

  2. Unity插件 - MeshEditor(八)模型镜像特效

    将静态模型(带MeshFilter)按指定轴向.指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之前模型的顶点, ...

  3. 高性能的Redis代理TwemProxy

    TwemProxy是一个Redis的中间件代理,具有很多有用的功能,可以暂时替代一部分Redis Cluster的功能: ²  支持和6479.之后相应地,配置好两个Redis实例并启动.现在就可以启 ...

  4. Node.js 撸第一个Web应用

    使用Node.js 创建Web 应用与使用PHP/Java 语言创建Web应用略有不同. 使用PHP/Java 来编写后台代码时,需要Apache 或者 Nginx 的HTTP 服务器,而接受请求和提 ...

  5. Android快速关联V4包的方式

    很多时候需要管理v4包,当然有很多种办法去关联.本人觉得最快速的方式,是通过添加配置文件的方式.只需要ctrl+c和ctrll+v就能解决了 方法如下: 1.新建一个android-support-v ...

  6. 详解EBS接口开发之应收款处理

    参考实例参考:杜春阳 R12应收模块收款API研究 (一)应收款常用标准表简介 1.1   常用标准表 如下表中列出了与应收款处理相关的表和说明: 表名 说明 其他信息 AR_BATCHES_ALL ...

  7. com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field 异常

    分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) 1.1.1. 前言 近期在使用ObjectMapper对象将jso ...

  8. bash shell while语法

    在编写脚本时,一定要注意空格 基本语法: while [ condition ] do command1 command2 command3 done condition为true时命令1到命令3将会 ...

  9. 19 Handler 子线程向主线程发送信息

    案例一 Message创建三种方法: package com.example.day19_handler_demo1; import android.os.Bundle; import android ...

  10. 熟悉java语言的基本使用:简单存款取款机制java实现

    最近一直没有项目做,于是我也不能这样闲着,我得开始学习新的技术,并且巩固以前自学的技术.以下就是我写的一个简单的java存取款代码,很简单,可能还有更简单的方法,目的是为了熟悉java的基本使用. p ...