一、代理模式定义:
- 目标对象不可访问,通过代理对象增强功能访问。
- 举个例子:
- 房东==>目标对象
- 房屋中介==>代理对象
- 租客==>客户端
二、代理模式的作用:
- 控制目标对象的访问。
- 举个例子:为了避免麻烦,房东(目标对象)拒绝与租客(客户端)频繁见面,房屋中介(代理对象)也会控制你与房屋中介(代理对象)见面。
- 增强功能。
- 举个例子:房屋中介(代理对象)会给租客(客户端)提供一系列房东(目标对象)提供不了的服务(功能)。
三、代理模式分类:
- 子类代理。
- 静态代理。
- 动态代理。
四、子类代理模式:
- 特点:
- 通过子类继承父类,子类在父类的基础上进行功能业务的增加。
- 子类代理实现:
- 父类BookService :
public class BookService {
public void buy(){
System.out.println("购书业务...");
}
}
- 子类SBookService:
public class SBookService extends BookService{
public void buy(){
System.out.println("购书前业务...");//增加功能
super.buy();//使用父类业务功能
System.out.println("购书完成...");
}
}
五、静态代理模式:
- 特点:
- 目标对象和代理对象实现同一个业务接口。
- 目标对象必须实现接口。
- 代理对象在程序运行前就已经存在。
- 能够灵活地进行目标对象的切换,却无法进行功能的灵活处理。(使用动态代理解决此问题)
- 代理对象无法实现目标对象的功能,却可以在目标对象的基础上增加其他功能。
- 静态代理实现:
- 业务接口:
package com.user.cailinhao.service;
/**
* 业务接口
*/
public interface Service {
//规定唱歌的业务功能
void sing();
}
- 目标对象1:刘德华
package com.user.cailinhao.service.impl;
import com.user.cailinhao.service.Service;
/**
* 刘德华:目标对象1
*/
public class SuperStarLiu implements Service {
@Override
public void sing() {
System.out.println("我是刘德华,我正在表演");
}
}
- 目标对象2:周润发
package com.user.cailinhao.service.impl;
import com.user.cailinhao.service.Service;
/**
* 周润发:目标对象2
*/
public class SuperStarZhou implements Service {
@Override
public void sing() {
System.out.println("我是周润发,我正在表演");
}
}
- 代理对象:假设刘德华和周润发公用同一个助理
package com.user.cailinhao.service.impl;
import com.user.cailinhao.service.Service;
/**
* 助理:代理对象
*/
public class Agent implements Service {
//面向接口编程,类中的成员变量设计为接口
public Service target;
//面向接口编程,方法的参数设计为接口,传入目标对象,完成代理功能
public Agent(Service target) {
this.target = target;
}
@Override
public void sing() {
System.out.println("预定时间");
System.out.println("预定场地");
//重点:业务功能必须由目标对象亲自实现
/*new SuperStarLiu().sing();这样就写死了,不灵活*/
//请谁谁唱,很灵活
target.sing();
System.out.println("结算费用");
}
}
- 客户端:
package com.user.cailinhao.test;
import com.user.cailinhao.service.Service;
import com.user.cailinhao.service.impl.Agent;
import com.user.cailinhao.service.impl.SuperStarLiu;
import org.junit.Test;
public class MyTest {
@Test
public void testAgent(){
/*
Service agent = new Agent();
agent.sing();
*/
}
public void testAgent1(){
//面向客户,具体谁来唱由客户选择
Service agent = new Agent(new SuperStarLiu());
agent.sing();
}
}
六、动态代理模式:
- 特点:
- 静态代理存在的问题:Service接口中如果添加其他方法,比如表演show(),会使得实现接口的目标对象和代理对象的代码都要改变。
- 代理对象在程序运行的过程中动态在内存构建,可以灵活地进行业务功能的切换。
七、JDK动态代理:
- 特点:
- 目标对象必须实现业务接口。
- JDK代理对象不需要实现业务接口。
- JDK动态代理的对象在程序运行前不存在。在程序运行时动态地在内存中构建。
- JDK动态代理灵活地进行业务功能的切换。
- 目标对象中的非接口中的方法不能被代理。
- 重点类说明:
- Proxy类:
它是java.lang.reflect.Proxy包下的类,它有一个方法Proxy.newProxy.newProxyInstance(…)专门用来生成动态代理对象。
public static Object newProxyInstance(ClassLoader lodaer,//类加载器,完成目标对象的加载
Class<?>[] interfaces,//目标对象实现的所有接口
InvocationHandler h,//类似于静态代理的Agent功能,代理的功能和目标对象功能的调用在这里
) throws IllegalArgumentException
{.......}
-
Method类:
反射机制,用来进行目标对象方法的反射调用。 -
InvocationHandler接口:
它是实现代理和业务功能的,我们在调用时使用匿名内部类实现。
- JDK动态代理实现:
- 代理工厂:重点!!!!!!!!!!!
package com.user.cailinhao.proxy;
import com.user.cailinhao.service.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理工厂用于动态生成代理对象Agent,通过传入target参数生成一个专门为target目标对象代理的Agent,通过实现接口的invoke方法实现代理对象Agent的额外功能
*/
public class ProxyFactory {
//面向接口编程,类中的成员变量设计为接口
Service target;
//面向接口编程,方法的参数设计为接口,传入目标对象,完成代理功能
public ProxyFactory(Service target) {
this.target = target;
}
//返回动态代理对象
public Object getAgent(){
return Proxy.newProxyInstance(//获取动态代理对象用这个方法
target.getClass().getClassLoader(),//类加载器,在JVM中完成目标对象的加载
target.getClass().getInterfaces(),//目标对象实现的所有接口,为了获取所有接口中的方法
new InvocationHandler() {//这是一个实现代理功能的接口,类似于静态代理的Agent功能,代理的功能和目标对象功能的调用在这里,采用匿名内部类实现
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//返回:目标对象方法的返回值
//proxy是创建好的代理对象
//method是目标对象的某个方法,可能是sing()、show()
//args是目标对象的方法的参数
//代理功能
System.out.println("预定时间");
System.out.println("预定场地");
//目标对象的功能
//target.sing();这么些不行,还是写死了,等同静态代理
Object obj = method.invoke(target,args);//反射机制给方法传参数,调用target对象的invoke方法并传参数args,来的演员想唱歌就唱歌,想跳舞就跳舞
//代理功能
System.out.println("结算费用");
return obj;//目标对象方法的返回值
}
}
);
}
}
- 业务接口:
package com.user.cailinhao.service;
/**
* 业务接口
*/
public interface Service {
void sing();
void show();
}
- 目标对象1:刘德华
package com.user.cailinhao.service.impl;
import com.user.cailinhao.service.Service;
/**
* 目标对象1:刘德华
*/
public class SuperStarLiu implements Service {
@Override
public void sing() {
System.out.println("我是刘德华,我在唱歌");
}
@Override
public void show() {
System.out.println("我是刘德华,我在表演");
}
}
- 目标对象2:周润发
package com.user.cailinhao.service.impl;
import com.user.cailinhao.service.Service;
/**
* 目标对象2:周润发
*/
public class SuperStarZhou implements Service {
@Override
public void sing() {
System.out.println("我是周润发,我在唱歌");
}
@Override
public void show() {
System.out.println("我是周润发,我在表演");
}
}
- 客户端:
package com.user.cailinhao.test;
import com.user.cailinhao.proxy.ProxyFactory;
import com.user.cailinhao.service.Service;
import com.user.cailinhao.service.impl.SuperStarLiu;
import org.junit.Test;
public class MyTest {
@Test
public void testJDK(){
ProxyFactory factory = new ProxyFactory(new SuperStarLiu());//目标对象创建代理对象
Service agent = (Service) factory.getAgent();//!!!!!强转成Service接口才能调用sing方法
agent.sing();
}
@Test
public void testJDK1(){
ProxyFactory factory = new ProxyFactory(new SuperStarLiu());//目标对象创建代理对象
Service agent = (Service) factory.getAgent();//!!!!!强转成Service接口才能调用sing方法
agent.show();
}
@Test
public void testJDK2(){
ProxyFactory factory = new ProxyFactory(new SuperStarLiu());//目标对象创建代理对象
Service agent = (Service) factory.getAgent();//!!!!!强转成Service接口才能调用sing方法
System.out.println(agent.getClass());//class jdk.proxy2.$Proxy4,这是一个JDK动态代理对象的类型
}
}
八、CBLib动态代理:
- 特点:
- 又称为子类动态代理,通过动态地在内存中构建子类对象,重写父类的方法进行代理功能的增强。
- 如果目标对象没有实现接口,则只能通过CGLib自雷代理来进行功能增强。
- CBLib动态代理实现:
- 业务接口:
package com.cailinhao.service;
/**
* 业务接口
*/
public interface Service {
void sing();
}
- 目标对象:
package com.cailinhao.service.impl;
import com.cailinhao.service.Service;
/**
* 目标对象1:刘德华
*/
public class SuperStarLiu implements Service {
@Override
public void sing() {
System.out.println("我是刘德华,我在唱歌");
}
}
- 代理对象:
package com.cailinhao.service.sub;
import com.cailinhao.service.impl.SuperStarLiu;
/**
* 代理对象
*/
public class SubSuperStarLiu extends SuperStarLiu {
@Override
public void sing() {
System.out.println("预定时间");
System.out.println("预定地点");
super.sing();
System.out.println("结算费用");
}
}
- 客户端:
package com.cailinhao;
import com.cailinhao.service.impl.SuperStarLiu;
import org.junit.Test;
public class MyTest {
@Test
public void testAgent(){
SuperStarLiu liu = new SuperStarLiu();
liu.sing();
}
}
九:面向接口编程:
- 类中的成员方法设计成接口。
- 方法的参数设计为接口。
- 方法返回值设计为接口。
- 使用时使接口指向实现类。