代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。
代理模式的使用场景:
1、当无法或者不想直接访问某个对象,或者访问某个对象存在困难是,就可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,代理对象与被代理对象需要实现相同的接口。
2、代理模式可以在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途,在调用实际对象的方法。
代理分为静态代理和动态代理:
静态代理:在编译的时候就已经将接口,代理类和被代理类确定下来;
动态代理:代理类在程序运行时,创建代理方式,即通过反射机制动态创建
相比于静态代理,动态代理的优势在于可以很方便的对代理类进行统一的处理,而不用修改代理类的方法。
代理模式的类图(盗用一下别人的图):
说明:
1、代理类(Proxy)和被代理类(RealSubject)都要实现相同的接口(Subject);
2、代理类要拥有被代理类的实例(图中箭头指的是被拥有类,代理类和被代理类是拥有关系);
3、被代理类用来执行具体的业务逻辑
静态代理的实例:
1、定义接口:
public interface Person {
//交学费
void getMeony();
}
2、被代理类:
/**
* 被代理类
*/
public class Student implements Person {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Student(String name) {
this.name = name;
}
@Override
public void getMeony() {
Log.e("----------->",name+"收了50块!");
}
}
3、代理类
/**
* 代理类,相当于班长
*/
public class ProxyStudent implements Person {
private Student student;//持有被代理类的引用
public ProxyStudent(Student student) {
if (student.getClass() == Student.class)
this.student = student;
}
//代理上交班费,调用被代理学生上交班费
@Override
public void getMeony() {
// 代理模式最主要的就是有一个公共接口(Person),一个具体的类(Student),一个代理类(StudentsProxy),
// 代理类持有具体类的实例,代为执行具体类实例方法。上面说到,代理模式就是在访问实际对象时引入一定程度的间接性,
// 因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。
// 就这个例子来说,加入班长在帮张三上交班费之前想要先反映一下张三最近学习有很大进步,通过代理模式很轻松就能办到
Log.e("--------------->",student.getName()+"学习比较认真");
student.getMeony();
}
}
4、使用
这里就是点击按钮来调用,简单的模拟哈哈
//静态代理
public void staticProxy(View view) {
Student student = new Student("学生");
ProxyStudent proxyStudent = new ProxyStudent(student);
proxyStudent.getMeony();
}
动态代理:
我们需要用到一个接口(InvocationHandler)和一个类(Proxy),代理类要实现这个InvocationHandler接口;通过Proxy来得到代理类
1、创建代理类
/**
* 动态代理的代理类
* 我们就要定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外:
*/
public class DynamicProxy implements InvocationHandler{
//持有被代理类的实例(要代理的真实对象)
private Student student ;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Student student) {
this.student = student;
}
/**
* 这块我们就可以进行上面说的统一处理类,就是那个间接性
*
* @param proxy 指代我们所代理的那个真实对象
* @param method 指代的是我们所要调用真实对象的某个方法的Method对象
* @param args 指代的是调用真实对象某个方法时接受的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
Log.e("---------->","哈哈动态代理类"+proxy.getClass().getName());
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(student,args);
//在代理真实对象后我们也可以添加一些自己的操作
Log.e("---------->","哈哈动态代理类wanshile");
return null;
}
}
2、得到代理类
public class ProxyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_proxy);
}
//静态代理
public void staticProxy(View view) {
Student student = new Student("学生");
ProxyStudent proxyStudent = new ProxyStudent(student);
proxyStudent.getMeony();
}
/**
* 在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,
* 那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型"转化"为这组接口中的任意一个,
* 因为这里的接口是Person类型,所以就可以将其"转化"为Person类型了.
*
* 同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,
* 也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
*
* 这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:
* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
*
* loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
*
* interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
*
* h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
*/
//动态代理
public void dynamicProxy(View view) {
Student student = new Student("ddd");
//得到动态的代理对象,Proxy类可以得到动态代理类
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, new DynamicProxy(student));
Log.e("---------->","---"+person.getClass().getName());
person.getMeony();
}
}
参考的博客:
java的动态代理机制详解
java动态代理实现与原理详细分析