代理模式

代理模式

即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。

代理模式也是SpringAOP的底层

代理模式分类:

  • 静态代理
  • 动态代理

代理模式_第1张图片


1、静态代理

角色分析:

  • 抽象角色(Rent):一般使用接口或者抽象类
  • 真实角色(Host):被代理的真实角色
  • 代理角色(Proxy):中介,真实的代理的角色,且其一般还会添加一些附属操作
  • 客户(User):访问代理对象的用户
  1. 新建一个抽象角色类:Rent.java

    package pers.mobian.proxy.demo1;
    
    public interface Rent {
        public void rent();
    }
    
  2. 新建一个真实角色类:Host.java

    package pers.mobian.proxy.demo1;
    
    public class Host implements Rent {
        
        @Override
        public void rent() {
            System.out.println("我是房东,我有房子出租");
        }
    }
    
  3. 新建一个代理角色类:Proxy.java

    package pers.mobian.proxy.demo1;
    
    public class Proxy implements Rent{
    
        private Host host = new Host();
        @Override
        public void rent() {
            seeHouse();
            host.rent();
            signContract();
        }
    
        private void seeHouse(){
            System.out.println("中介带你看房子");
        }
        private void signContract(){
            System.out.println("中介帮忙签合同");
        }
    }
    
  4. 新建一个用户测试类:User.java

    package pers.mobian.proxy.demo1;
    
    public class User {
        public static void main(String[] args) {
            Proxy proxy = new Proxy();
            proxy.rent();
        }
    }
    
  5. 测试结果

    中介带你看房子
    我是房东,我有房子出租
    中介帮忙签合同
    

代理模式的优点:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共的业务交给了代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便进行集中管理

缺点:

  • 一个真实角色会产生一个代理角色,开发效率变低

2、静态代理加强版

角色分析:

  • 抽象角色(UserService):包含增删改查四个方法
  • 真实角色(UserServiceImpl):增删改查的具体实现
  • 代理角色(Proxy):中介,真实的代理的角色,添加打印功能
  • 客户(User):访问代理对象的用户
  1. 抽象角色:UserService.java

    package pers.mobian.proxy.demo2;
    
    public interface UserService {
        public void add();
    
        public void delte();
    
        public void update();
    
        public void selet();
    
    }
    
  2. 真实角色:UserServiceImpl.java

    package pers.mobian.proxy.demo2;
    
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            System.out.println("使用了增加方法");
        }
    
        @Override
        public void delte() {
            System.out.println("使用了删除方法");
        }
    
        @Override
        public void update() {
            System.out.println("使用了修改方法");
        }
    
        @Override
        public void selet() {
            System.out.println("使用了查找方法");
        }
    }
    
  3. 代理角色:Proxy.java

    package pers.mobian.proxy.demo2;
    
    public class Proxy implements UserService {
        private  UserServiceImpl userServiceImpl;
    
        public void setUserServiceImpl(UserServiceImpl userServiceImpl) {
            this.userServiceImpl = userServiceImpl;
        }
    
        public Proxy(UserServiceImpl userServiceImpl) {
            this.userServiceImpl = userServiceImpl;
        }
    
        public Proxy() {
        }
    
        @Override
        public void add() {
            userServiceImpl.add();
            show("add");
        }
    
        @Override
        public void delte() {
            userServiceImpl.delte();
            show("delte");
        }
    
        @Override
        public void update() {
            userServiceImpl.update();
            show("update");
        }
    
        @Override
        public void selet() {
            userServiceImpl.selet();
            show("selet");
        }
    
    
        public void show(String method){
            System.out.println(method+"方法使用成功");
        }
    }
    
  4. 客户:User.java

    package pers.mobian.proxy.demo2;
    
    public class User {
        public static void main(String[] args) {
            UserServiceImpl userServiceImpl = new UserServiceImpl();
    
            Proxy proxy = new Proxy(userServiceImpl);
            proxy.add();
            proxy.delte();
            proxy.selet();
            proxy.update();
    
        }
    }
    
  5. 测试结果

    使用了增加方法
    add方法使用成功
    使用了删除方法
    delte方法使用成功
    使用了查找方法
    selet方法使用成功
    使用了修改方法
    update方法使用成功
    

实际开发中的模型(仅供参考)

代理模式_第2张图片


3、动态代理

  • 动态代理和静态代理角色相同
  • 动态代理的代理是动态生成的,不是我们直接写出来的
  • 动态代理分类:
    • 基于接口的:JDK动态代理
    • 基于类:cglib
    • java字节码实现:javassist

需要了解两个类:Proxy:代理 , InvocationHandler:调用处理程序

动态代理的好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共的业务交给了代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便进行集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要实现了同一个接口即可

角色分析:

  • 抽象角色(Rent):一般使用接口或者抽象类
  • 真实角色(Host):被代理的真实角色
  • 动态代理角色(ProxyInvocationHander):可以动态代理一个接口下的所有操作
  • 客户(User):访问代理对象的用户
  1. 抽象角色:Rent.java

    package pers.mobian.proxy.demo3;
    
    public interface Rent {
        public void rent();
    }
    
  2. 真实角色:Host.java

    package pers.mobian.proxy.demo3;
    
    public class Host implements Rent {
    
        @Override
        public void rent() {
            System.out.println("我是房东,我有房子出租");
        }
    }
    
  3. 动态代理角色:ProxyInvocationHander.java

    package pers.mobian.proxy.demo3;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyInvocationHander implements InvocationHandler {
        //被代理的接口
        private Rent rent;
        public void setRent(Rent rent) {
            this.rent = rent;
        }
    
        //通过接口得到代理类
        public Object getProxy() {
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
        }
    
        //对代理实例添加附属操作,并返回结果
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            seeHouse();
            Object result = method.invoke(rent, args);
            signContract();
            return result;
        }
    
    
        private void seeHouse(){
            System.out.println("中介带你看房子");
        }
        private void signContract(){
            System.out.println("中介帮忙签合同");
        }
    }
    
  4. 客户:User.java

    package pers.mobian.proxy.demo3;
    
    public class User {
        public static void main(String[] args) {
            Rent rent = new Host();
            ProxyInvocationHander pih = new ProxyInvocationHander();
            pih.setRent(rent);
            Rent proxy = (Rent) pih.getProxy();
            proxy.rent();
        }
    }
    
  5. 测试结果

    中介带你看房子
    我是房东,我有房子出租
    中介帮忙签合同
    

4、动态代理类加强版

角色分析:

  • 抽象角色(UserService):包含增删改查四个方法
  • 真实角色(UserServiceImpl):增删改查的具体实现
  • 代理角色(Proxy):中介,真实的代理的角色,添加打印功能
  • 客户(User):访问代理对象的用户
  1. 抽象角色:UserService.java

    package pers.mobian.proxy.demo2;
    
    public interface UserService {
        public void add();
    
        public void delte();
    
        public void update();
    
        public void selet();
    
    }
    
  2. 真实角色:UserServiceImpl.java

    package pers.mobian.proxy.demo2;
    
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            System.out.println("使用了增加方法");
        }
    
        @Override
        public void delte() {
            System.out.println("使用了删除方法");
        }
    
        @Override
        public void update() {
            System.out.println("使用了修改方法");
        }
    
        @Override
        public void selet() {
            System.out.println("使用了查找方法");
        }
    }
    
  3. 代理角色:Proxy.java

    package pers.mobian.proxy.demo4;
    
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyInvocationHander implements InvocationHandler {
        //被代理的接口
        private UserService userService;
    
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        //通过接口得到代理类
        public Object getProxy() {
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
        }
    
        //对代理实例添加附属操作,并返回结果
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(userService, args);
            //通过反射获得具体的方法名
            log(method.getName());
            return result;
        }
    
        public void log(String method) {
            System.out.println(method+"方法使用成功");
        }
    }
    
  4. 客户:User.java

    package pers.mobian.proxy.demo4;
    
    public class User {
        public static void main(String[] args) {
            UserService userServiceImpl = new UserServiceImpl();
            ProxyInvocationHander pih = new ProxyInvocationHander();
            pih.setUserService(userServiceImpl);
            UserService userService = (UserService)pih.getProxy();
            userService.add();
            userService.delte();
            userService.update();
            userService.selet();
        }
    }
    
  5. 测试结果

    使用了增加方法
    add方法使用成功
    使用了删除方法
    delte方法使用成功
    使用了修改方法
    update方法使用成功
    使用了查找方法
    selet方法使用成功
    

总结:在静态代理的基础上,每次添加一个真实角色,就需要一个对应的代理类来执行相应的代理操作。当使用动态代理类以后,不再拥有实际的代理类,而是使用真实角色的功能,即抽象角色(也就是接口),最终使用户能够控制所有的继承了这个接口的真实类。解决了静态代理的缺点,避免了代码的臃肿。


5、改良版的动态代理类模板

将所有的接口变成Object类,继而达到复用的效果

package pers.mobian.proxy.demo4;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHander implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setUserService(Object target) {
        this.target = target;
    }

    //通过接口得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    //对代理实例添加附属操作,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(target, args);
        return result;
    }
}

你可能感兴趣的:(设计模式)