[关闭]
@natsumi 2017-09-26T03:45:29.000000Z 字数 32784 阅读 876

设计模式

Design_Pattern Java Android 信意涵得offer


参考:
Android 源码中的设计模式(你需要知道的设计模式全在这里)

1. 面向对象的六大原则

1.1 单一职责原则

所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。通俗的说,即一个类只负责一项职责,将一组相关性很高的函数、数据封装到一个类中。

1.2 开闭原则

对于扩展是开放的,这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。

对于修改是关闭的,对模块行为进行扩展时,不必改动模块的源代码。

通俗的说,尽量通过扩展的方式实现系统的升级维护和新功能添加,而不是通过修改已有的源代码。

1.3 里氏替换原则

使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。任何基类可以出现的地方,子类一定可以出现。在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。

在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

1.4 依赖倒置原则

程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合(各个模块之间相互传递的参数声明为抽象类型,而不是声明为具体的实现类)。

1.5 接口隔离原则

一个类对另一个类的依赖应该建立在最小的接口上。其原则是将非常庞大的、臃肿的接口拆分成更小的更具体的接口。

1.6 迪米特原则(最少知识原则)

就是说一个对象应当对其他对象有尽可能少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,不关心被耦合或调用的类的内部实现,只负责调用你提供的方法。

2. Singleton(单例模式)

保证在Java应用程序中,一个类Class只有一个实例存在。

优点:

使用情况:

2.1 实现

  1. public class Test02 {
  2. /**
  3. * 单例模式,饿汉(类初始化时进行实例化)式,线程安全
  4. * <p>
  5. * 优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题;
  6. * <p>
  7. * 缺点是:当类SingletonTest被加载的时候,会初始化static的instance,
  8. * 静态变量被创建并分配内存空间,从这以后,这个static的instance对象便
  9. * 一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量
  10. * 被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
  11. */
  12. public static class Singleton {
  13. private final static Singleton INSTANCE = new Singleton();
  14. private Singleton() {
  15. }
  16. public static Singleton getInstance() {
  17. return INSTANCE;
  18. }
  19. }
  20. /**
  21. * 单例模式,懒汉(在第一次调用是实例化)式,线程不安全
  22. * <p>
  23. * 优点是:写起来比较简单,当类SingletonTest被加载的时候,
  24. * 静态变量static的instance未被创建并分配内存空间,
  25. * 当getInstance方法第一次被调用时,初始化instance变量,
  26. * 并分配内存,因此在某些特定条件下会节约了内存;
  27. * <p>
  28. * 缺点是:并发环境下很可能出现多个SingletonTest实例。
  29. */
  30. public static class Singleton2 {
  31. private static Singleton2 instance = null;
  32. private Singleton2() {
  33. }
  34. public static Singleton2 getInstance() {
  35. if (instance == null) {
  36. instance = new Singleton2();
  37. }
  38. return instance;
  39. }
  40. }
  41. /**
  42. * 单例模式,懒汉式,线程安全,多线程环境下效率不高
  43. * <p>
  44. * 优点是:使用synchronized关键字避免多线程访问时,出现多个SingletonTest实例。
  45. * <p>
  46. * 缺点是:同步方法频繁调用时,效率略低。
  47. */
  48. public static class Singleton3 {
  49. private static Singleton3 instance = null;
  50. private Singleton3() {
  51. }
  52. public static synchronized Singleton3 getInstance() {
  53. if (instance == null) {
  54. instance = new Singleton3();
  55. }
  56. return instance;
  57. }
  58. }
  59. /**
  60. * 单例模式,饿汉式,变种,线程安全
  61. */
  62. public static class Singleton4 {
  63. private static Singleton4 instance = null;
  64. static {
  65. instance = new Singleton4();
  66. }
  67. private Singleton4() {
  68. }
  69. public static Singleton4 getInstance() {
  70. return instance;
  71. }
  72. }
  73. /**
  74. * 单例模式,懒汉式,使用静态内部类,线程安全【推荐】
  75. * <p>
  76. * 当getInstance方法第一次被调用的时候,它第一次读取
  77. * SingletonHolder.INSTANCE,内部类SingletonHolder
  78. * 得到初始化;而这个类在装载并被初始化的时候,会初始化它
  79. * 的静态域,从而创建Singleton的实例,由于是静态的域,
  80. * 因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来
  81. * 保证它的线程安全性。
  82. * <p>
  83. * 优点:getInstance方法并没有被同步,并且只是执行一个域
  84. * 的访问,因此延迟初始化并没有增加任何访问成本
  85. */
  86. public static class Singleton5 {
  87. private final static class SingletonHolder {
  88. private static final Singleton5 INSTANCE = new Singleton5();
  89. }
  90. private Singleton5() {
  91. }
  92. public static Singleton5 getInstance() {
  93. return SingletonHolder.INSTANCE;
  94. }
  95. }
  96. /**
  97. * 使用枚举方式,线程安全【推荐】
  98. * https://zybuluo.com/natsumi/note/692892
  99. * <p>
  100. * 传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、
  101. * 公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破
  102. * 坏单例),目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,
  103. * 因为JVM会保证enum不能被反射并且构造器方法只执行一次。
  104. * <p>
  105. * 1.从Java1.5开始支持;
  106. * 2.无偿提供序列化机制;
  107. * 3.绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候;
  108. */
  109. public enum Singleton6 {
  110. INSTANCE;//理解为public static final Singleton6 INSTANCE;
  111. Singleton6() {//这个方法默认就是private的
  112. //do something
  113. }
  114. }
  115. /**
  116. * Singleton3改进版,使用双重校验锁,避免频繁加锁,线程安全【推荐】
  117. */
  118. public static class Singleton7 {
  119. private volatile static Singleton7 instance = null;
  120. private Singleton7() {
  121. }
  122. public static Singleton7 getInstance() {
  123. if (instance == null) {
  124. synchronized (Singleton7.class) {
  125. if (instance == null) {
  126. instance = new Singleton7();
  127. }
  128. }
  129. }
  130. return instance;
  131. }
  132. }
  133. public static void main(String[] args) {
  134. System.out.println(Singleton.getInstance() == Singleton.getInstance());
  135. System.out.println(Singleton2.getInstance() == Singleton2.getInstance());
  136. System.out.println(Singleton3.getInstance() == Singleton3.getInstance());
  137. System.out.println(Singleton4.getInstance() == Singleton4.getInstance());
  138. System.out.println(Singleton5.getInstance() == Singleton5.getInstance());
  139. System.out.println(Singleton6.INSTANCE == Singleton6.INSTANCE);
  140. System.out.println(Singleton7.getInstance() == Singleton7.getInstance());
  141. }
  142. }

2.1.1 枚举单例实现

  1. public class Singleton6{
  2. }
  3. public enum Whatever {
  4. INSTANCE;
  5. private Singleton6 instance;
  6. Whatever() {
  7. instance = new Singleton6();
  8. }
  9. public Singleton6 getInstance() {
  10. return instance;
  11. }
  12. }

http://blog.csdn.net/yy254117440/article/details/52305175
这篇文章中用枚举类实现单例是这样写的,就是单例的类并不是那个枚举类,而是用枚举实现另一个类的单例。这个在面试的时候被问过。。然而现在想想还是不太对。。
这样写的话实例的获取方式是Whatever.INSTANCE.getInstance()

反编译后就会发现,使用枚举其实和使用静态类内部加载方法原理类似。枚举会被编译成如下形式:

  1. public final class T extends Enum{
  2. //...
  3. }

Enum是Java提供给编译器的一个用于继承的类。枚举量的实现其实是public static final T 类型的未初始化变量。如果枚举量有伴随参数并且手动添加了构造器,那么将会解析成一个静态的代码块在类加载时对变量进行初始化。所以,如果用枚举去实现一个单例,这样的加载时间其实有点类似于饿汉模式,并没有起到lazy-loading的作用。

2.2 android中的Singleton

软键盘管理的InputMethodManager

  1. public final class InputMethodManager {
  2. //...
  3. static InputMethodManager sInstance;
  4. //...
  5. InputMethodManager(IInputMethodManager service, Looper looper) {
  6. mService = service;
  7. mMainLooper = looper;
  8. mH = new H(looper);
  9. mIInputContext = new ControlledInputConnectionWrapper(looper,
  10. mDummyInputConnection, this);
  11. }
  12. /**
  13. * Retrieve the global InputMethodManager instance, creating it if it
  14. * doesn't already exist.
  15. * @hide
  16. */
  17. public static InputMethodManager getInstance() {
  18. synchronized (InputMethodManager.class) {
  19. if (sInstance == null) {
  20. IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
  21. IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
  22. sInstance = new InputMethodManager(service, Looper.getMainLooper());
  23. }
  24. return sInstance;
  25. }
  26. }
  27. //...
  28. }

使用的是懒汉单例模式(类似Singleton7,线程安全),类似的还有AccessibilityManager(View获得点击、焦点、文字改变等事件的分发管理,对整个系统的调试、问题定位等)

注意Application并不算是单例模式

  1. public class Application extends ContextWrapper implements ComponentCallbacks2 {
  2. //...
  3. public Application() {
  4. super(null);
  5. }
  6. //...
  7. }

在Application源码中,其构造方法是公有的,意味着可以生出多个Application实例,但为什么Application能实现一个app只存在一个实例呢?请看下面:

在ContextWrapper源码中,ContextWrapper构造函数传入的base为null,就算有多个Application实例,但是没有通过attach()绑定相关信息,没有上下文环境,然并卵。

  1. public class ContextWrapper extends Context {
  2. Context mBase;
  3. public ContextWrapper(Context base) {
  4. mBase = base;
  5. }
  6. /**
  7. * Set the base context for this ContextWrapper. All calls will then be
  8. * delegated to the base context. Throws
  9. * IllegalStateException if a base context has already been set.
  10. *
  11. * @param base The new base context for this wrapper.
  12. */
  13. protected void attachBaseContext(Context base) {
  14. if (mBase != null) {
  15. throw new IllegalStateException("Base context already set");
  16. }
  17. mBase = base;
  18. }
  19. //...
  20. }

3. Factory(工厂模式)

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。对同一个接口的实现类进行管理和实例化创建

3.1 举个栗子

动物Animal,它有行为move()。有两个实现类cat和dog。为了统一管理和创建我们设计一个工厂模式。同时两个子类有各自的行为,Cat有eatFish(),Dog有eatBone()。

结构图: 这里写图片描述

Animal接口:

  1. interface animal {
  2. void move();
  3. }

Cat类:

  1. public class Cat implements Animal{
  2. @Override
  3. public void move() {
  4. // TODO Auto-generated method stub
  5. System.out.println("我是只肥猫,不爱动");
  6. }
  7. public void eatFish() {
  8. System.out.println("爱吃鱼");
  9. }
  10. }

Dog类:

  1. public class Dog implements Animal{
  2. @Override
  3. public void move() {
  4. // TODO Auto-generated method stub
  5. System.out.println("我是狗,跑的快");
  6. }
  7. public void eatBone() {
  8. System.out.println("爱吃骨头");
  9. }
  10. }

那么现在就可以建一个工厂类(Factory.java)来对实例类进行管理和创建了.

  1. public class Factory {
  2. //静态工厂方法
  3. //多处调用,不需要实例工厂类
  4. public static Cat produceCat() {
  5. return new Cat();
  6. }
  7. public static Dog produceDog() {
  8. return new Dog();
  9. }
  10. //当然也可以一个方法,通过传入参数,switch实现
  11. }

使用:

  1. Animal cat = Factory.produceCat();
  2. cat.move();
  3. //-----------------------------
  4. Dog dog = Factory.produceDog();
  5. dog.move();
  6. dog.eatBone();

工厂模式在业界运用十分广泛,如果都用new来生成对象,随着项目的扩展,animal还可以生出许多其他儿子来,当然儿子还有儿子,同时也避免不了对以前代码的修改(比如加入后来生出儿子的实例),怎么管理,想着就是一团糟。

  1. Animal cat = Factory.produceCat();

这里实例化了Animal但不涉及到Animal的具体子类(减少了它们之间的偶合联系性),达到封装效果,也就减少错误修改的机会。Java面向对象的原则,封装(Encapsulation)和分派(Delegation)告诉我们:具体事情做得越多,越容易范错误,

一般来说,这样的普通工厂就可以满足基本需求。但是我们如果要新增一个Animal的实现类panda,那么必然要在工厂类里新增了一个生产panda的方法。就违背了 闭包的设计原则(对扩展要开放对修改要关闭),于是有了抽象工厂模式。

3.2 Abstract Factory(抽象工厂)

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。啥意思?就是把生产抽象成一个接口,每个实例类都对应一个工厂类(普通工厂只有一个工厂类),同时所有工厂类都继承这个生产接口。

生产接口Provider:

  1. interface Provider {
  2. Animal produce();
  3. }

每个产品都有自己的工厂 CatFactory:

  1. public class CatFactory implements Provider{
  2. @Override
  3. public Animal produce() {
  4. // TODO Auto-generated method stub
  5. return new Cat();
  6. }
  7. }

DogFactory:

  1. public class DogFactory implements Provider{
  2. @Override
  3. public Animal produce() {
  4. // TODO Auto-generated method stub
  5. return new Dog();
  6. }
  7. }

产品生产:

  1. Provider provider = new CatFactory();
  2. Animal cat =provider.produce();
  3. cat.move();

现在我们要加入panda,直接新建一个pandaFactory就行了,这样我们系统就非常灵活,具备了动态扩展功能。

3.3 Android中的Factory

比如AsyncTask的抽象工厂实现:

工厂的抽象接口:

  1. /**
  2. * An object that creates new threads on demand. Using thread factories
  3. * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
  4. * enabling applications to use special thread subclasses, priorities, etc.
  5. *
  6. * <p>
  7. * The simplest implementation of this interface is just:
  8. * <pre> {@code
  9. * class SimpleThreadFactory implements ThreadFactory {
  10. * public Thread newThread(Runnable r) {
  11. * return new Thread(r);
  12. * }
  13. * }}</pre>
  14. *
  15. * The {@link Executors#defaultThreadFactory} method provides a more
  16. * useful simple implementation, that sets the created thread context
  17. * to known values before returning it.
  18. * @since 1.5
  19. * @author Doug Lea
  20. */
  21. public interface ThreadFactory {
  22. /**
  23. * Constructs a new {@code Thread}. Implementations may also initialize
  24. * priority, name, daemon status, {@code ThreadGroup}, etc.
  25. *
  26. * @param r a runnable to be executed by new thread instance
  27. * @return constructed thread, or {@code null} if the request to
  28. * create a thread is rejected
  29. */
  30. Thread newThread(Runnable r);
  31. }

AsyncTask中工厂类的实现:

  1. private static final ThreadFactory sThreadFactory = new ThreadFactory() {
  2. private final AtomicInteger mCount = new AtomicInteger(1);
  3. public Thread newThread(Runnable r) {
  4. return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
  5. }
  6. };

我们可以创建另外类似的工厂,生产某种专门的线程(多线程),非常容易扩展。 当然,android中的应用还有很多(比如BitmapFactory),有兴趣的小伙伴可以去扒一扒。
BitmapFactory

4. Adapter(适配器模式)

将一个类的接口转换成客户希望的另外一个接口。

我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办?使用Adapter,在这两种接口之间创建一个混合接口。

优点

缺点

模式中的角色

4.1 举个栗子

  1. // 需要适配的类
  2. class Adaptee {
  3. public void specificRequest() {
  4. System.out.println("需要适配的类");
  5. }
  6. }
  1. // 目标接口
  2. interface Target {
  3. public void request();
  4. }

实现方式:

4.1.1 对象适配器(采用对象组合方式实现)

  1. // 适配器类实现标准接口
  2. class Adapter implements Target{
  3. // 直接关联被适配类
  4. private Adaptee adaptee;
  5. // 可以通过构造函数传入具体需要适配的被适配类对象
  6. public Adapter (Adaptee adaptee) {
  7. this.adaptee = adaptee;
  8. }
  9. public void request() {
  10. // 这里是使用委托的方式完成特殊功能
  11. this.adaptee.specificRequest();
  12. }
  13. }
  14. // 测试类
  15. public class Client {
  16. public static void main(String[] args) {
  17. // 需要先创建一个被适配类的对象作为参数
  18. Target adapter = new Adapter(new Adaptee());
  19. adapter.request();
  20. }
  21. }

如果Target不是接口而是一个具体的类的情况,这里的Adapter直接继承Target就可以了。

4.1.2 类的适配器模式(采用继承实现)

  1. // 适配器类继承了被适配类同时实现标准接口
  2. class Adapter extends Adaptee implements Target{
  3. public void request() {
  4. super.specificRequest();
  5. }
  6. }
  7. // 测试类
  8. public class Client {
  9. public static void main(String[] args) {
  10. // 使用适配类
  11. Target adapter = new Adapter();
  12. adapter.request();
  13. }
  14. }

如果Target和Adaptee都是接口,并且都有实现类。可以通过Adapter实现两个接口来完成适配。

还有一种叫PluggableAdapters,可以动态的获取几个adapters中一个。使用Reflection技术,可以动态的发现类中的Public方法。

4.2 Android中的Adapter

android中的Adapter就有很多了,这个大家都经常用。Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View。

Adapter的继承结构

BaseAdapter是Adapter,ListAdapter、SpinnerAdapter都是Target ,mDataSetObservable是Adaptee,采用对象组合方式。

BaseAdapter的源码:

  1. /**
  2. * Common base class of common implementation for an {@link Adapter} that can be
  3. * used in both {@link ListView} (by implementing the specialized
  4. * {@link ListAdapter} interface) and {@link Spinner} (by implementing the
  5. * specialized {@link SpinnerAdapter} interface).
  6. */
  7. public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
  8. private final DataSetObservable mDataSetObservable = new DataSetObservable();
  9. //...
  10. public void registerDataSetObserver(DataSetObserver observer) {
  11. mDataSetObservable.registerObserver(observer);
  12. }
  13. public void unregisterDataSetObserver(DataSetObserver observer) {
  14. mDataSetObservable.unregisterObserver(observer);
  15. }
  16. /**
  17. * Notifies the attached observers that the underlying data has been changed
  18. * and any View reflecting the data set should refresh itself.
  19. */
  20. public void notifyDataSetChanged() {
  21. mDataSetObservable.notifyChanged();
  22. }
  23. /**
  24. * Notifies the attached observers that the underlying data is no longer valid
  25. * or available. Once invoked this adapter is no longer valid and should
  26. * not report further data set changes.
  27. */
  28. public void notifyDataSetInvalidated() {
  29. mDataSetObservable.notifyInvalidated();
  30. }
  31. //...
  32. }

4.3 Java中的Adapter

TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说TreeSet里面有一个TreeMap。HashSet和HashMap也是类似的关系。

  1. // TreeSet是对TreeMap的简单包装
  2. public class TreeSet<E> extends AbstractSet<E>
  3. implements NavigableSet<E>, Cloneable, java.io.Serializable
  4. {
  5. ......
  6. private transient NavigableMap<E,Object> m;
  7. // Dummy value to associate with an Object in the backing Map
  8. private static final Object PRESENT = new Object();
  9. public TreeSet() {
  10. this.m = new TreeMap<E,Object>();// TreeSet里面有一个TreeMap
  11. }
  12. ......
  13. public boolean add(E e) {
  14. return m.put(e, PRESENT)==null;
  15. }
  16. ......
  17. }

详见:https://github.com/xietiantian/JCFInternals/blob/master/markdown/5-TreeSet%20and%20TreeMap.md

5. Chain of Responsibility(责任链模式)

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。    发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。 

编程中的小体现:

  1. if(a<10){
  2. //...
  3. }else if (a<20){
  4. //...
  5. }else if(a<30){
  6. //...
  7. }else{
  8. //...
  9. }

程序必须依次扫描每个分支进行判断,找到对应的分支进行处理。

优点

缺点

5.1 Android中的Chain of Responsibility

触摸、按键等各种事件的传递

View事件传递

Android View 事件分发机制 源码解析 (上)
http://blog.csdn.net/lmj623565791/article/details/38960443
Android ViewGroup事件分发机制
http://blog.csdn.net/lmj623565791/article/details/39102591
图解 Android 事件分发机制
http://www.jianshu.com/p/e99b5e8bd67b

6. Observer(观察者模式)

有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的(依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。)。

观察者模式的组成

6.1 举个栗子

言语苍白,上代码:

  1. //抽象观察者
  2. public interface Observer
  3. {
  4. public void update(String str);
  5. }
  1. //具体观察者
  2. public class ConcreteObserver implements Observer{
  3. @Override
  4. public void update(String str) {
  5. // TODO Auto-generated method stub
  6. System.out.println(str);
  7. }
  8. }
  1. //抽象主题
  2. public interface Subject
  3. {
  4. public void addObserver(Observer observer);
  5. public void removeObserver(Observer observer);
  6. public void notifyObservers(String str);
  7. }
  1. //具体主题
  2. public class ConcreteSubject implements Subject{
  3. // 存放观察者
  4. private List<Observer> list = new ArrayList<Observer>();
  5. @Override
  6. public void addObserver(Observer observer) {
  7. // TODO Auto-generated method stub
  8. list.add(observer);
  9. }
  10. @Override
  11. public void removeObserver(Observer observer) {
  12. // TODO Auto-generated method stub
  13. list.remove(observer);
  14. }
  15. @Override
  16. public void notifyObservers(String str) {
  17. // TODO Auto-generated method stub
  18. for(Observer observer:list){
  19. observer.update(str);
  20. }
  21. }
  22. }

下面是测试类:

  1. /**
  2. * @author fanrunqi
  3. */
  4. public class Test {
  5. public static void main(String[] args) {
  6. //一个主题
  7. ConcreteSubject eatSubject = new ConcreteSubject();
  8. //两个观察者
  9. ConcreteObserver personOne = new ConcreteObserver();
  10. ConcreteObserver personTwo = new ConcreteObserver();
  11. //观察者订阅主题
  12. eatSubject.addObserver(personOne);
  13. eatSubject.addObserver(personTwo);
  14. //通知开饭了
  15. eatSubject.notifyObservers("开饭啦");
  16. }
  17. }

“关于代码你有什么想说的?” “没有,都在代码里了” “(⊙o⊙)哦.....”

6.2 Android中的Observer

6.2.1 ContentResolver和ContentObserver

观察者模式在android中运用的也比较多,最熟悉的ContentObserver。

抽象类ContentResolver中(Subject)

  1. public abstract class ContentResolver {
  2. //...
  3. //注册观察者
  4. /**
  5. * Register an observer class that gets callbacks when data identified by a
  6. * given content URI changes.
  7. *
  8. * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
  9. * for a whole class of content.
  10. * @param notifyForDescendants When false, the observer will be notified whenever a
  11. * change occurs to the exact URI specified by <code>uri</code> or to one of the
  12. * URI's ancestors in the path hierarchy. When true, the observer will also be notified
  13. * whenever a change occurs to the URI's descendants in the path hierarchy.
  14. * @param observer The object that receives callbacks when changes occur.
  15. * @see #unregisterContentObserver
  16. */
  17. public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
  18. @NonNull ContentObserver observer) {
  19. Preconditions.checkNotNull(uri, "uri");
  20. Preconditions.checkNotNull(observer, "observer");
  21. registerContentObserver(
  22. ContentProvider.getUriWithoutUserId(uri),
  23. notifyForDescendants,
  24. observer,
  25. ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
  26. }
  27. //取消观察者
  28. /**
  29. * Unregisters a change observer.
  30. *
  31. * @param observer The previously registered observer that is no longer needed.
  32. * @see #registerContentObserver
  33. */
  34. public final void unregisterContentObserver(@NonNull ContentObserver observer) {
  35. Preconditions.checkNotNull(observer, "observer");
  36. try {
  37. IContentObserver contentObserver = observer.releaseContentObserver();
  38. if (contentObserver != null) {
  39. getContentService().unregisterContentObserver(
  40. contentObserver);
  41. }
  42. } catch (RemoteException e) {
  43. }
  44. }
  45. //...
  46. //还有很多个notifyChange方法
  47. }

抽象类ContentObserver中(Observer)

  1. public abstract class ContentObserver {
  2. /**
  3. * This method is called when a content change occurs.
  4. * <p>
  5. * Subclasses should override this method to handle content changes.
  6. * </p>
  7. *
  8. * @param selfChange True if this is a self-change notification.
  9. */
  10. public void onChange(boolean selfChange) {
  11. // Do nothing. Subclass should override.
  12. }
  13. /**
  14. * This method is called when a content change occurs.
  15. * Includes the changed content Uri when available.
  16. * <p>
  17. * Subclasses should override this method to handle content changes.
  18. * To ensure correct operation on older versions of the framework that
  19. * did not provide a Uri argument, applications should also implement
  20. * the {@link #onChange(boolean)} overload of this method whenever they
  21. * implement the {@link #onChange(boolean, Uri)} overload.
  22. * </p><p>
  23. * Example implementation:
  24. * <pre><code>
  25. * // Implement the onChange(boolean) method to delegate the change notification to
  26. * // the onChange(boolean, Uri) method to ensure correct operation on older versions
  27. * // of the framework that did not have the onChange(boolean, Uri) method.
  28. * {@literal @Override}
  29. * public void onChange(boolean selfChange) {
  30. * onChange(selfChange, null);
  31. * }
  32. *
  33. * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
  34. * {@literal @Override}
  35. * public void onChange(boolean selfChange, Uri uri) {
  36. * // Handle change.
  37. * }
  38. * </code></pre>
  39. * </p>
  40. *
  41. * @param selfChange True if this is a self-change notification.
  42. * @param uri The Uri of the changed content, or null if unknown.
  43. */
  44. public void onChange(boolean selfChange, Uri uri) {
  45. onChange(selfChange);
  46. }
  47. /**
  48. * Dispatches a change notification to the observer. Includes the changed
  49. * content Uri when available and also the user whose content changed.
  50. *
  51. * @param selfChange True if this is a self-change notification.
  52. * @param uri The Uri of the changed content, or null if unknown.
  53. * @param userId The user whose content changed. Can be either a specific
  54. * user or {@link UserHandle#USER_ALL}.
  55. *
  56. * @hide
  57. */
  58. public void onChange(boolean selfChange, Uri uri, int userId) {
  59. onChange(selfChange, uri);
  60. }
  61. }

观察特定Uri引起的数据库的变化,继而做一些相应的处理(最终都调用的第一个函数)

6.2.2 DataSetObserver

其实这个我们一直在用,只是没意识到。
4.2节中提到BaseAdapter内封装了一个DataSetObservable对象,这就是一个subject

DataSetObservable源码

  1. /**
  2. * A specialization of {@link Observable} for {@link DataSetObserver}
  3. * that provides methods for sending notifications to a list of
  4. * {@link DataSetObserver} objects.
  5. */
  6. public class DataSetObservable extends Observable<DataSetObserver> {
  7. /**
  8. * Invokes {@link DataSetObserver#onChanged} on each observer.
  9. * Called when the contents of the data set have changed. The recipient
  10. * will obtain the new contents the next time it queries the data set.
  11. */
  12. public void notifyChanged() {
  13. synchronized(mObservers) {
  14. // since onChanged() is implemented by the app, it could do anything, including
  15. // removing itself from {@link mObservers} - and that could cause problems if
  16. // an iterator is used on the ArrayList {@link mObservers}.
  17. // to avoid such problems, just march thru the list in the reverse order.
  18. for (int i = mObservers.size() - 1; i >= 0; i--) {
  19. mObservers.get(i).onChanged();
  20. }
  21. }
  22. }
  23. /**
  24. * Invokes {@link DataSetObserver#onInvalidated} on each observer.
  25. * Called when the data set is no longer valid and cannot be queried again,
  26. * such as when the data set has been closed.
  27. */
  28. public void notifyInvalidated() {
  29. synchronized (mObservers) {
  30. for (int i = mObservers.size() - 1; i >= 0; i--) {
  31. mObservers.get(i).onInvalidated();
  32. }
  33. }
  34. }
  35. }

向BaseAdater注册、注销一个DataSetObserver实例时调用DataSetObservable基类的注册和注销方法。DataSetObservable是发布者,上面DataSetObservable源码中的两个方法分别实现发布DataSet变更和失效的消息,通过调用DataSetObserver的onChanged()和onInvalidated()方法实现。

DataSetObserver 的源码:

  1. /**
  2. * Receives call backs when a data set has been changed, or made invalid. The typically data sets
  3. * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s.
  4. * DataSetObserver must be implemented by objects which are added to a DataSetObservable.
  5. */
  6. public abstract class DataSetObserver {
  7. /**
  8. * This method is called when the entire data set has changed,
  9. * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
  10. */
  11. public void onChanged() {
  12. // Do nothing
  13. }
  14. /**
  15. * This method is called when the entire data becomes invalid,
  16. * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
  17. * {@link Cursor}.
  18. */
  19. public void onInvalidated() {
  20. // Do nothing
  21. }
  22. }

DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。

订阅DataSet变化消息的订阅者应该是展现DataSet的View,果然我们可以在AdapterView中找到一个内部类AdapterDataSetObserver继承DataSetObserver。

  1. public abstract class AdapterView<T extends Adapter> extends ViewGroup {
  2. //...
  3. class AdapterDataSetObserver extends DataSetObserver {
  4. private Parcelable mInstanceState = null;
  5. @Override
  6. public void onChanged() {
  7. //...
  8. }
  9. @Override
  10. public void onInvalidated() {
  11. //...
  12. }
  13. public void clearSavedState() {
  14. mInstanceState = null;
  15. }
  16. }
  17. //...
  18. }

AbsListView持有一个AdapterDataSetObserver类的对象mDataSetObserver。

  1. public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
  2. ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
  3. ViewTreeObserver.OnTouchModeChangeListener,
  4. RemoteViewsAdapter.RemoteAdapterConnectionCallback {
  5. //...
  6. AdapterDataSetObserver mDataSetObserver;
  7. //...
  8. }

小结:ListView、GridView等AdapterView中持有订阅者对象,而BaseAdapter中持有发布者对象。

7. Builder(建造者模式)

是将一个复杂的对象的构建与它的表示分离(同构建不同表示),使得同样的构建过程可以创建不同的表示。

一个人活到70岁以上,都会经历这样的几个阶段:婴儿,少年,青年,中年,老年。并且每个人在各个阶段肯定是不一样的,世界上不存在两个人在人生的这5个阶段的生活完全一样,但是活到70岁以上的人,都经历了这几个阶段是肯定的。实际上这是一个比较经典的建造者模式的例子了。

将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。

建造者模式通常包括下面几个角色

与抽象工厂的区别

在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。

优点:

使用场合:

7.1 举个栗子 

Product和产品的部分Part接口

  1. public interface Product { }
  2. public interface Part { }

Builder:

  1. public interface Builder {
  2. void buildPartOne();
  3. void buildPartTwo();
  4. Product getProduct();
  5. }

ConcreteBuilder:

  1. //具体建造工具
  2. public class ConcreteBuilder implements Builder {
  3. Part partOne, partTwo;
  4. public void buildPartOne() {
  5. //具体构建代码
  6. }
  7. public void buildPartTwo() {
  8. //具体构建代码
  9. }
  10. public Product getProduct() {
  11. //返回最后组装的产品
  12. }
  13. }

Director :

  1. public class Director {
  2. private Builder builder;
  3. public Director( Builder builder ) {
  4. this.builder = builder;
  5. }
  6. public void construct() {
  7. builder.buildPartOne();
  8. builder.buildPartTwo();
  9. }
  10. }

建造:

  1. ConcreteBuilder builder = new ConcreteBuilder();
  2. Director director = new Director(builder);
  3. //开始各部分建造 
  4. director.construct();
  5. Product product = builder.getResult();

7.2 Android中的Builder

android中的Dialog就使用了Builder Pattern,下面来看看AlertDialog的部分源码。

  1. public static class Builder {
  2. private final AlertController.AlertParams P;
  3. public Builder(Context context) {
  4. this(context, resolveDialogTheme(context, 0));
  5. }
  6. public Builder(Context context, int themeResId) {
  7. P = new AlertController.AlertParams(new ContextThemeWrapper(
  8. context, resolveDialogTheme(context, themeResId)));
  9. }
  10. //...
  11. }

AlertDialog的Builder是一个静态内部类,没有定义Builder的抽象接口。对AlertDialog设置的属性会保存在Build类的成员变量P(AlertController.AlertParams)中。

Builder类中部分方法:

  1. /**
  2. * Set the title using the given resource id.
  3. *
  4. * @return This Builder object to allow for chaining of calls to set methods
  5. */
  6. public Builder setTitle(@StringRes int titleId) {
  7. P.mTitle = P.mContext.getText(titleId);
  8. return this;
  9. }
  10. /**
  11. * Set the title displayed in the {@link Dialog}.
  12. *
  13. * @return This Builder object to allow for chaining of calls to set methods
  14. */
  15. public Builder setTitle(CharSequence title) {
  16. P.mTitle = title;
  17. return this;
  18. }
  19. /**
  20. * Set the message to display using the given resource id.
  21. *
  22. * @return This Builder object to allow for chaining of calls to set methods
  23. */
  24. public Builder setMessage(@StringRes int messageId) {
  25. P.mMessage = P.mContext.getText(messageId);
  26. return this;
  27. }
  28. /**
  29. * Set the message to display.
  30. *
  31. * @return This Builder object to allow for chaining of calls to set methods
  32. */
  33. public Builder setMessage(CharSequence message) {
  34. P.mMessage = message;
  35. return this;
  36. }

而show()方法会返回一个结合上面设置的dialog实例

  1. /**
  2. * Creates an {@link AlertDialog} with the arguments supplied to this
  3. * builder and immediately displays the dialog.
  4. * <p>
  5. * Calling this method is functionally identical to:
  6. * <pre>
  7. * AlertDialog dialog = builder.create();
  8. * dialog.show();
  9. * </pre>
  10. */
  11. public AlertDialog show() {
  12. final AlertDialog dialog = create();
  13. dialog.show();
  14. return dialog;
  15. }
  16. /**
  17. * Set a listener to be invoked when the positive button of the dialog is pressed.
  18. * @param textId The resource id of the text to display in the positive button
  19. * @param listener The {@link DialogInterface.OnClickListener} to use.
  20. *
  21. * @return This Builder object to allow for chaining of calls to set methods
  22. */
  23. public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
  24. P.mPositiveButtonText = P.mContext.getText(textId);
  25. P.mPositiveButtonListener = listener;
  26. return this;
  27. }
  28. /**
  29. * Set a listener to be invoked when the positive button of the dialog is pressed.
  30. * @param text The text to display in the positive button
  31. * @param listener The {@link DialogInterface.OnClickListener} to use.
  32. *
  33. * @return This Builder object to allow for chaining of calls to set methods
  34. */
  35. public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
  36. P.mPositiveButtonText = text;
  37. P.mPositiveButtonListener = listener;
  38. return this;
  39. }

简单建造:

  1. new AlertDialog.Builder(context)
  2. .setTitle("标题")
  3. .setMessage("消息框")
  4. .setPositiveButton("确定", null)
  5. .show();

8. Memento(备忘录模式)

备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。

备忘录模式所涉及的角色有三个:

8.1 举个栗子

发起人

  1. public class Originator {
  2. private String state;
  3. /**
  4. * 工厂方法,返回一个新的备忘录对象
  5. */
  6. public Memento createMemento(){
  7. return new Memento(state);
  8. }
  9. /**
  10. * 将发起人恢复到备忘录对象所记载的状态
  11. */
  12. public void restoreMemento(Memento memento){
  13. this.state = memento.getState();
  14. }
  15. public String getState() {
  16. return state;
  17. }
  18. public void setState(String state) {
  19. this.state = state;
  20. System.out.println("当前状态:" + this.state);
  21. }
  22. }

备忘录

  1. public class Memento {
  2. private String state;
  3. public Memento(String state){
  4. this.state = state;
  5. }
  6. public String getState() {
  7. return state;
  8. }
  9. public void setState(String state) {
  10. this.state = state;
  11. }
  12. }

管理者

  1. public class Caretaker {
  2. private Memento memento;
  3. /**
  4. * 备忘录的取值方法
  5. */
  6. public Memento retrieveMemento(){
  7. return this.memento;
  8. }
  9. /**
  10. * 备忘录的赋值方法
  11. */
  12. public void saveMemento(Memento memento){
  13. this.memento = memento;
  14. }
  15. }

使用:

  1. Originator o = new Originator();
  2. Caretaker c = new Caretaker();
  3. //改变负责人对象的状态
  4. o.setState("On");
  5. //创建备忘录对象,并将发起人对象的状态储存起来
  6. c.saveMemento(o.createMemento());
  7. //修改发起人的状态
  8. o.setState("Off");
  9. //恢复发起人对象的状态
  10. o.restoreMemento(c.retrieveMemento());

不需要了解对象的内部结构的情况下备份对象的状态,方便以后恢复。

8.2 Android中的Memento

Activity的onSaveInstanceState和onRestoreInstanceState就是通过Bundle(相当于备忘录对象)这种序列化的数据结构来存储Activity的状态,至于其中存储的数据结构,这两个方法不用关心。

还是看一下源码:
留着注释学习一下调用场合,虽然都是on开头的方法,但是跟生命周期中的回调方法不同。

  1. /**
  2. * Called to retrieve per-instance state from an activity before being killed
  3. * so that the state can be restored in {@link #onCreate} or
  4. * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
  5. * will be passed to both).
  6. *
  7. * <p>This method is called before an activity may be killed so that when it
  8. * comes back some time in the future it can restore its state. For example,
  9. * if activity B is launched in front of activity A, and at some point activity
  10. * A is killed to reclaim resources, activity A will have a chance to save the
  11. * current state of its user interface via this method so that when the user
  12. * returns to activity A, the state of the user interface can be restored
  13. * via {@link #onCreate} or {@link #onRestoreInstanceState}.
  14. *
  15. * <p>Do not confuse this method with activity lifecycle callbacks such as
  16. * {@link #onPause}, which is always called when an activity is being placed
  17. * in the background or on its way to destruction, or {@link #onStop} which
  18. * is called before destruction. One example of when {@link #onPause} and
  19. * {@link #onStop} is called and not this method is when a user navigates back
  20. * from activity B to activity A: there is no need to call {@link #onSaveInstanceState}
  21. * on B because that particular instance will never be restored, so the
  22. * system avoids calling it. An example when {@link #onPause} is called and
  23. * not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
  24. * the system may avoid calling {@link #onSaveInstanceState} on activity A if it isn't
  25. * killed during the lifetime of B since the state of the user interface of
  26. * A will stay intact.
  27. *
  28. * <p>The default implementation takes care of most of the UI per-instance
  29. * state for you by calling {@link android.view.View#onSaveInstanceState()} on each
  30. * view in the hierarchy that has an id, and by saving the id of the currently
  31. * focused view (all of which is restored by the default implementation of
  32. * {@link #onRestoreInstanceState}). If you override this method to save additional
  33. * information not captured by each individual view, you will likely want to
  34. * call through to the default implementation, otherwise be prepared to save
  35. * all of the state of each view yourself.
  36. *
  37. * <p>If called, this method will occur before {@link #onStop}. There are
  38. * no guarantees about whether it will occur before or after {@link #onPause}.
  39. *
  40. * @param outState Bundle in which to place your saved state.
  41. *
  42. * @see #onCreate
  43. * @see #onRestoreInstanceState
  44. * @see #onPause
  45. */
  46. protected void onSaveInstanceState(Bundle outState) {
  47. outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
  48. Parcelable p = mFragments.saveAllState();
  49. if (p != null) {
  50. outState.putParcelable(FRAGMENTS_TAG, p);
  51. }
  52. getApplication().dispatchActivitySaveInstanceState(this, outState);
  53. }
  54. /**
  55. * This method is called after {@link #onStart} when the activity is
  56. * being re-initialized from a previously saved state, given here in
  57. * <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
  58. * to restore their state, but it is sometimes convenient to do it here
  59. * after all of the initialization has been done or to allow subclasses to
  60. * decide whether to use your default implementation. The default
  61. * implementation of this method performs a restore of any view state that
  62. * had previously been frozen by {@link #onSaveInstanceState}.
  63. *
  64. * <p>This method is called between {@link #onStart} and
  65. * {@link #onPostCreate}.
  66. *
  67. * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
  68. *
  69. * @see #onCreate
  70. * @see #onPostCreate
  71. * @see #onResume
  72. * @see #onSaveInstanceState
  73. */
  74. protected void onRestoreInstanceState(Bundle savedInstanceState) {
  75. if (mWindow != null) {
  76. Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
  77. if (windowState != null) {
  78. mWindow.restoreHierarchyState(windowState);
  79. }
  80. }
  81. }

9. Prototype(原型模式)

能快速克隆出一个与已经存在对象类似的另外一个我们想要的新对象。

工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

分为深拷贝和浅拷贝。深拷贝就是把对象里面的引用的对象也要拷贝一份新的对象,并将这个新的引用对象作为拷贝的对象引用(多读两遍)。

一般使用原型模式有个明显的特点,就是实现cloneable的clone()方法。

在Intent源码中:

  1. @Override
  2. public Object clone() {
  3. return new Intent(this);
  4. }

这里Intent通过实现Cloneable接口来实现原型拷贝。

10. Strategy(策略模式)

定义:有一系列的算法,将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化。策略模式其实就是多态的一个淋漓精致的体现。

举例:

在android中不同Animation动画的实现,主要是依靠Interpolator(插值器)的不同而实现的。

  1. /**
  2. * Sets the acceleration curve for this animation. Defaults to a linear
  3. * interpolation.
  4. *
  5. * @param i The interpolator which defines the acceleration curve
  6. * @attr ref android.R.styleable#Animation_interpolator
  7. */
  8. public void setInterpolator(Interpolator i) {
  9. mInterpolator = i;
  10. }

11. Template(模板模式)

定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。实现流程已经确定,实现细节由子类完成。

举例:

12. Proxy(代理模式)

为其他对象提供一种代理以控制对这个对象的访问。

代理:在出发点到目的地之间有一道中间层。

举例:Android跨进程通信方式 ,Binder机制。

Java层Binder机制详解
http://blog.csdn.net/yuanzeyao/article/details/12954641

13. Interpreter(解释器模式)

定义语言的文法,并且建立一个解释器来解释该语言中的句子。

比如Android中通过PackageManagerService来解析AndroidManifest.xml中定义的Activity、service等属性。

PackageManagerService的启动过程分析
http://blog.csdn.net/yuanzeyao/article/details/42215521

14. State(状态模式)

行为是由状态来决定的,不同状态下有不同行为。

注意:状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立可相互替换的。

举例:不同的状态执行不同的行为,当WIFI开启时,自动扫描周围的接入点,然后以列表的形式展示;当WIFI关闭时则清空。

15. Command(命令模式)

我们有很多命令,把它们放在一个下拉菜单中,用户通过先选择菜单再选择具体命令,这就是Command模式。

本来用户(调用者)是直接调用这些命令的,在菜单上打开文档,就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了。

显然这样做的好处是符合封装的特性,降低耦合度,有利于代码的健壮性 可维护性 还有复用性。Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式。

android底层逻辑对事件的转发处理就用到了Command模式。

16. Iterator(迭代模式)

提供一种方法顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。

举例:

  1. cursor.moveToFirst();

16. Composite(组合模式)  

将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

Android中View的结构是树形结构,每个ViewGroup包含一系列的View,而ViewGroup本身又是View。这是Android中非常典型的组合模式。

17. Flyweight(共享模式/享元模式)

避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。

面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞大,比如,字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗费内存,那么我们还是要"求同存异",找出这些对象群的共同点,设计一个元类,封装可以被共享的类,另外,还有一些特性是取决于应用(context),是不可共享的,这是Flyweight中两个重要概念内部状态intrinsic和外部状态extrinsic之分。

说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(模式池)来存放内部状态的对象。

Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度。

举例:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注