Android 设计模式
对于开发人员,设计模式是必须过的一道坎,而且在自己面试过程中也是常常的被问到,但是过了这到坎,你的整体代码水平都会上升一个档次,而且在Android的源码中也用到很多的设计模式。其中我们常用的有单例、工厂、观察者、代理、命令、适配器、合成、访问者
单例模式
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
这样做有以下几个优点
- 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
- 保持程序运行的时候该中始终只有一个实例存在内存中
单例模式注意事项:
只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。不要做断开单例类对象与类中静态引用的危险操作。多线程使用单例使用共享资源时,注意线程安全问题。
eg:EventBus 单例模式
private static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
要保证单例,需要做一下几步
- 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
- 必须定义一个静态函数获得该单例
- 单例使用volatile修饰
- 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (EventBus.class) 里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。
构造者模式(Build模式)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 eg:
public class Person {
private String name;
private int age;
private double height;
private double weight;
privatePerson(Builder builder) {
this.name=builder.name;
this.age=builder.age;
this.height=builder.height;
this.weight=builder.weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
static class Builder{
private String name;
private int age;
private double height;
private double weight;
public Builder name(String name){
this.name=name;
return this;
}
public Builder age(int age){
this.age=age;
return this;
}
public Builder height(double height){
this.height=height;
return this;
}
public Builder weight(double weight){
this.weight=weight;
return this;
}
public Person build(){
return new Person(this);
}
}
}
于是我们可以创建:
Person.Builder builder=new Person.Builder();
Person person=builder
.name("张三")
.age(18)
.height(178.5)
.weight(67.4)
.build();
在Android中, Builder模式也是被大量的运用:
AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog dialog=builder.setTitle("标题")
.setIcon(android.R.drawable.ic_dialog_alert)
.setView(R.layout.myview)
.setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create();
dialog.show();
OkHttp中也有一个Builder
Request.Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
.url("")
.post(body)
.build();
观察者模式
定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
在android中的应用的观察者模式
Button btn=new Button(this);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("TAG","buttonOnClick");
}
});
原型模式
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
代理模式
1.静态代理
public interface IBuyCar {
//买车
void buyCar();
}
public class Customer implements IBuyCar {
private int cash;//购车款
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
@Override
public void buyCar() {
Log.e("buyCar", "买一辆车花费了-->" + cash + "元");
}
}
public class BuyCarProxy implements IBuyCar{
private Customer customer;//接收买车客户
public BuyCarProxy(Customer customer){
this.customer=customer;//接收买车客户
}
@Override
public void buyCar() {//实现为客户买车
customer.buyCar();
}
}
Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();
通过代理模式实现权限控制
@Override
public void buyCar() {//实现为客户买车
int cash=customer.getCash();
if(cash<100000){
Log.e("buyCar","你的钱不够买一辆车");
return;
}
customer.buyCar();
}
Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();
Customer customer1 =new Customer();
customer1.setCash(90000);
BuyCarProxy buyCarProxy1 =new BuyCarProxy(customer1);
buyCarProxy1.buyCar();
2.动态代理机制
以上讲的都是代理模式的静态实现,所谓静态代理就是自己要为要代理的类写一个代理类,或者用工具为其生成的代理类,总之,就是程序运行前就已经存在的编译好的代理类,这样有时候会觉得非常麻烦,也导致非常的不灵活,相比静态代理,动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。
首先我们要声明一个动态代理类,实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
// 被代理类的实例
Object obj;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object obj) {
this.obj = obj;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.obj, args);
/*
* after : doSomething();
*/
return result;
}
}
//我们要代理的真实对象
Customer customer = new Customer();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(customer);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数customer.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
IBuyCar buyCar = (IBuyCar) Proxy.newProxyInstance(handler.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);
buyCar.buyCar();
动态代理好处 使用Java动态代理机制的好处:
1、减少编程的工作量:假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。
2、系统扩展性和维护性增强,程序修改起来也方便多了(一般只要改代理处理器类就行了)。