Android常用设计模式

316 阅读5分钟

单例

类在内存中仅存在一个实例对象,7种写法:

1、饿汉式

在类加载时就完成初始化,不是懒加载

public class Singleton {  
     private static Singleton instance = new Singleton();  
     private Singleton (){
     }
     public static Singleton getInstance() {  
     return instance;  
     }  
 }

2、懒汉式(线程不安全)

在第一次调用时初始化,多线程中不安全

public class Singleton {  
      private static Singleton instance;  
      private Singleton (){
      }   
      public static Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
 }

3、懒汉式(线程安全)—加synchronized关键字

public class Singleton {  
      private static Singleton instance;  
      private Singleton (){
      }
      public static synchronized Singleton getInstance() {  
      if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
 }

每次调用都需要进行同步,造成不必要的开销。但Android中使用同步少,不建议

4、双重检查

public class Singleton {  
      private volatile static Singleton instance;  
      private Singleton (){
      }   
      public static Singleton getInstance() {  
      if (instance== null) {  
          synchronized (Singleton.class) {  
          if (instance== null) {  
              instance= new Singleton();  
          }  
         }  
     }  
     return instance;  
     }  
 }

getInstance方法中对instance进行了两次判空,第一次是为了不必要的同步,第二次是在instance等于null的情况下才创建实例。必须加第二份null判断,因为第一个null判断没有加锁,可能在第一个条件判断后出现同步问题。

volatile关键字作用:

1)禁止指令重排

2)内存可见,避免缓存不一致

5、静态内部类单例

public class Singleton { 
    private Singleton(){
    }
      public static Singleton getInstance(){  
        return SingletonHolder.sInstance;  
    }  
    private static class SingletonHolder {  
        private static final Singleton sInstance = new Singleton();  
    }  
}

第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder 并初始化sInstance ,这样不仅能确保线程安全也能保证Singleton类的唯一性。

观察者模式(发布者-订阅者模式)

发布者:Observable ,承担通知任务

订阅者:Observer ,承担具体实施

步骤:

1、发布者里面维护了一个订阅者数组,订阅者先在发布者里进行注册,即将Observer添加到数组中

2、当发布者数据更新时,发布者调用通知方法,通知所有订阅者。即遍历发布者中的数组,逐个执行订阅者中的方法。

使用场景

1、关联行为场景。关联行为是可拆分的,分步骤的。

2、事件多级触发场景

消息队列eventBus ,listview中Adapter刷新数据

优点和缺点

优点:解耦,各自的变换都不互相影响

缺点:运行效率问题。

回调函数与观察者模式

回调函数是一对一的观察者模式,而一般的观察着模式发布者与订阅者是一对多的。


建造者模式—Builder模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。将创建复杂对象的过程和它的部件解耦。

优点:容易扩展、可读性好

缺点:产生多余的Builder对象开销

工厂模式

统一生成某个对象的类,称为工厂。在Android系统里应用很多,比如Activity、Service等的构造过程,都是由一个工厂类来初始化生成的。

好处:降低耦合、清晰、函数重载(多态的一种)

缺点:可实例化的类型在编译期间已被确定。如果增加新类型,需要修改工厂。

代理模式—(委托模式)

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

使用场景:为一个对象在不同的地址空间提供局部代表,这样系统可以将Server部分的事项隐藏。eg:Binder机制,hook机制

1、静态代理

代理类持有一个真实被代理者对象,代理类执行的方法里面调用的都是真实被代理类实现的方法。

public class ProxySubject implements Subject {
	private Subject subject;
	
	 public ProxySubject(Subject subject) {
		 this.subject = subject;
	 }

	@Override
	public void visit() {
		subject.visit();
	}

}

在client端调用

public class Client {
	public static void main(String[] args) {
		ProxySubject subject = new ProxySubject(new RealSubject());
		subject.visit();
	}

}


2、动态代理

动态代理是在代码运行时通过反射来动态的生成代理类的对象。

在编码阶段不需要知道代理谁,代理谁我们将会在代码运行时决定。

/**
 * 动态代理 
 * 1、编写一个委托类的接口,即静态代理的(Subject接口) 
 * 2、实现一个真正的委托类,即静态代理的(RealSubject类)
 * 3、创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
 * 4、在测试类中,生成动态代理的对象
 *
 */
public class DynamicProxy implements InvocationHandler {
	private Object object;

	public DynamicProxy(Object object) {
		this.object = object;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = method.invoke(object, args);
		return result;
	}

}

在client端调用

public class Client {
	public static void main(String[] args) {
		Subject realSubject = new RealSubject();
		DynamicProxy proxy = new DynamicProxy(realSubject);
		ClassLoader classLoader = realSubject.getClass().getClassLoader();
		Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
		subject.visit();
	}

}

原理分析:

通过反射方式,在内存中动态生成proxy对象,最终subject类中方法调用都会走Proxy对象的invoke方法,这样就实现了对Subject中方法的hook。

装饰者模式

目的:扩展,使用组合而不是继承

是一种结构型设计模式,不改变原有类文件和继承关系,动态地扩展一个对象的功能。是继承的替代方案之一。通过创建一个包装对象,来包裹真实的对象。

eg:ContextWrapper

好处:

  • 通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  • 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
  • 具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”

缺点:基类变化会影响装饰类

与代理模式比较

代理模式和装饰模式有点像,都是持有了被代理或者被装饰对象的引用。它们两个最大的不同就是装饰模式对引用的对象增加了功能,而代理模式只是对引用对象进行了控制却没有对引用对象本身增加功能