9.3 设计模式类别
设计模式分为以下3种类型。
(1)创建型模式
包括单例模式、抽象工厂模式、建造者模式、工厂模式和原型模式。
(2)结构型模式
包括适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式和代理模式。
(3)行为型模式
包括模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式和访问者模式。
9.3.1 单例模式
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。此模式适用于只创建一个对象,以避免产生多个对象消耗过多资源及只应该创建一个对象的场景。
如加载图片的ImageLoad对象、线程池对象、缓存对象、网络请求对象、数据库对象、文件对象、登录状态对象、日志对象及一些公共数据对象,都可以用单例模式实现,这样也减少了静态和全局变量的使用。
APP向服务器发送请求的时候,在有些界面会发送多个请求给服务器,这时如果网络或服务器端出错,会接连弹出多个提示框。这种提示框也可以使用单列模式创建,这样即使发送了多个请求,但只显示一个出错提示框,从而改善用户体验。
实现单例模式的方式有饿汉和懒汉等方式,如果考虑到多线程的情况,这些方式都有不足之处,推荐使用以下方式实现。
public class MyApplication { private MyApplication () {} public static MyApplication getInstance() { return MyApplicationHolder.sInstance; } private static class MyApplicationHolder { private static final MyApplication sInstance = new MyApplication (); } }
第一次加载MyApplication类时,不会初始化sInstance,只有在第一次调用MyApplication的getInstance方法时,才会导致sInstance被初始化。在第一次调用getInstance方法时会加载MyApplicationHolder类,这种方式不仅能确保线程安全,也能保证单例对象的唯一性,同时也延迟了对象的实例化。
9.3.2 Builder模式
Builder模式将一个复杂对象的构建与它的表示形式分离,使得同样的构建过程可以创建不同的表示形式。
Android中AlertDialog的初始化配置就使用了Builder模式,加载图片的库ImageLoader和HTTP请求的初始化配置等也使用了Builder模式。
9.3.3 原型模式
原型模式允许通过复制现有的实例来创建新的实例。当创建给定的类的实例过程较复杂或消耗较多资源时,就可使用原型模式。在Android中,可以通过Cloneable接口实现。
在电商APP中,修改用户信息、修改购物车详情、修改订单详情和修改用户编辑的文本内容等可使用原型模式。
原型模式的核心问题就是对原始对象进行拷贝,使用时需要注意深、浅拷贝的问题。建议尽量使用深拷贝,这样可以避免操作副本时影响原始对象。
9.3.4 工厂方法模式
工厂方法模式定义了一个用于创建对象的接口,让子类决定将哪一个类实例化,使一个类的实例化延迟到其子类。
在电商APP中,创建各类商品对象和各类订单对象时就可以使用工厂模式。
代码示例:
public abstract class Product { Public abstract void method(); } public class ConcreteProductA extends class Product { @Override public void method() { … } } public class ConcreteProductB extends class Product { @Override public void method() { … } } //@param clz 产品类型 //@return 具体的产品对象 public abstract class Factory { public abstract <T extends Product> T createProduct (Class<T> clz); } public class ConcreteFactory extends class Factory { @Override public abstract <T extends Product> T createProduct (Class<T> clz) { Product p = null; try{ p = (Product) Class.format(clz.getName()).newInstance(); }catch (Exception e) { … } return (T) p; } } public class Client { public static void main(String args) { Factory factory = new ConcreteFactory(); Product p = factory. createProduct(ConcreteProductA.class); } }
9.3.5 策略模式
策略模式定义一系列的算法,并把每一个算法封装起来,且使它们可相互替换,使得算法的变化可独立于使用它的客户。
在电商APP中,各类商品列表的排序功能及计算各类商品的费用等功能(不同商品的单价和总价的计算方式可能不同)可以使用策略模式。
9.3.6 状态模式
状态模式允许对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
电商APP的订单对象包含有多种状态,以及用户登录对象包含已登录和未登录的两种状态,这两个对象的具体实现都可以使用状态模式。
9.3.7 命令模式
命令模式将请求封装为对象,从而使用不同的请求或队列来参数化其他对象。命令模式也支持可撤销的操作。
游戏开发和菜单功能的开发都可使用命令模式。
9.3.8 观察者模式
观察者模式定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
Android系统的BroadcastReceiver组件和GUI系统就使用了观察者模式。
9.3.9 备忘录模式
备忘录模式在不破坏封装性的前提下,存储对象的关键状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。
当用户把APP切换到后台时,需要保存当前界面的数据,以便在切换回前台时恢复数据,此外游戏和文本编辑中的存档功能,都可使用备忘录模式。
9.3.10 迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而且不需暴露该对象的内部表示。
此模式适用于遍历一个容器对象,如数组、链表和Map等。
9.3.11 模板方法模式
模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中,使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。
如在控件中显示图片时,图片可能来源于网络、内存或本地缓存,但显示图片的整个流程是一样的,就可以用模板方法模式。
9.3.12 代理模式
代理模式为另一个对象提供一个替身,以控制对这个对象的访问。
Android系统的Binder和Notification机制就使用了代理模式。
9.3.13 组合模式
组合模式将对象组合成树形结构以表示“整体/部分”的层次结构。它能让客户以一致的方式处理个别对象及对象组合。
Android系统的文件系统、View和ViewGroup系统就使用了组合模式。
9.3.14 适配器模式
适配器模式将一个类的接口转换成客户希望的另外一个接口,从而使原本接口不兼容的两个类能够在一起工作。
在APP中为了实现某个功能,往往需要集成第三方库或SDK,而这些第三方库或SDK可能会采用不同厂商的产品,为了替换方便,就可以使用适配器模式。对于同一份数据,用户可能选择不同的显示方式,如不同风格的菜单也可采用适配器模式。
9.3.15 外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。它定义了一个高层接口,让子系统更加容易使用。
封装API给调用者使用的时候,可以使用外观模式。
9.3.16 桥接模式
桥接模式将实现和抽象放在两个不同的类层次中,从而使它们可以独立改变。
电商APP在计算商品总价时,依赖商品数量和促销政策这两个因素。同一种促销政策,对于不同的商品数量,其促销折扣也不一样,在计算商品总价时就会有N种情况,此时就可使用桥接模式。