其他分享
首页 > 其他分享> > 代理模式

代理模式

作者:互联网

概述

定义

优点

缺点

分类

静态代理

案例A

我们来分析租房,首先房东可能手里有很多的房子可以出租,但是他不想自己亲自打广告,接待访客,他只想给房子然后拿钱,那么他就应该去找房屋中介,对于我们的房客而言,我们将不在直接接触房东,我们只能找到中介,然后中介再找房东

那么结果这么分析,我们可以分析出以下几个角色

那么我们开始代码实现,房东可以做很多事情,如卖房子,租房子,所以出租这个事情应该定义为接口让房东自己去实现

//租房
public interface Rent {
    void rent();
}

然后定义房东

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.print("房东要出租房子!");
    }
}

然后定义代理对象,首先他应该也有租房这一个方法,而中介的租房能力是来自房东的,且中介在租房这个过程中应该还需要联系房东,他不能直接去继承房东,我们应该用组合的思想,将房东交给中介,而且中介还会做一些其他附属操作

public class Proxy implements Rent {
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    public void seeHouse() {
        System.out.println("中介带你去看房");
    }

    @Override
    public void rent() {
        host.rent();
        System.out.println("来自中介");
    }
	
    public void pare() {
        System.out.println("中介收取租金");
    }
}

模拟房客找中介租房

public static void main(String[] args) {
    Host host = new Host();
    Proxy proxy = new Proxy(host);
    proxy.seeHouse();
    proxy.pare();
    proxy.rent();
}

image-20210307171014863

案例B

对于我们经常写的Service,其中实现了若干的方法,当我们现在需要增加日志功能,在每一个方法前面打印一行语句,按照以往的经验,我们就需要去手动在每一个方法前面再新增一行日志语句,但是这样很明显违背了我们的开闭原则,更好的解决方案就是使用代理,这也是面向切面编程的Spring AOP的核心思想

代码实现,首先是接口类

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

然后是对接口进行实现

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("add");
    }

    @Override
    public void delete() {
        System.out.println("delete");
    }

    @Override
    public void update() {
        System.out.println("update");
    }

    @Override
    public void query() {
        System.out.println("query");
    }
}

调用

image-20210307172032401

现在需要在每一行语句前面新增一个日志,就不用一行一行去加了,新建一个代理

@Data
public class UserServiceProxy implements UserService {
    private UserServiceImpl userService;

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    private void log(String logName){
        System.out.println("使用了"+logName+"方法");
    }
}

调用

public static void main(String[] args) {
    UserServiceImpl userService = new UserServiceImpl();
    UserServiceProxy userServiceProxy = new UserServiceProxy();
    userServiceProxy.setUserService(userService);
    userServiceProxy.add();
    userServiceProxy.delete();
    userServiceProxy.update();
    userServiceProxy.query();
}

image-20210307172603374

动态代理

对于静态代理而言,我们没出现一个被代理都想,都得去新建一个代理,这样代码量就会翻倍,开发效率变低,那么我们就使用动态代理去解决这个问题,我们可以利用反射动态的去管理对象,也就是动态代理类是动态生成的,而不是直接写好的

对于动态代理分为两大类

基于接口

需要了解两个类

新增一个InvocationHandlerProxy对象,我们需要用它来帮我们动态生成代理类

@Data
public class InvocationHandlerProxy implements InvocationHandler {
    //被代理的接口
    private 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 {
        //动态代理的本质就是使用反射机制实现
        return method.invoke(rent, args);
    }
}

调用

public static void main(String[] args) {
    Host host = new Host();
    //代理角色,现在没有
    InvocationHandlerProxy invocationHandlerProxy = new InvocationHandlerProxy();
    //通过调用程序处理角色来处理我们要调用的接口对象
    invocationHandlerProxy.setRent(host);
    //这里就是动态生成的代理
    Rent rent = (Rent) invocationHandlerProxy.getProxy();
    rent.rent();
}

image-20210307175240568

现在中介需要做一些附加操作,就直接放在调用处理程序中即可

@Data
public class InvocationHandlerProxy implements InvocationHandler {
    //被代理的接口
    private 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 o = method.invoke(rent, args);
        System.out.println("来自中介");
        pare();
        return o;
    }

    public void seeHouse() {
        System.out.println("中介带你看房子");
    }

    public void pare() {
        System.out.println("收取中介费");
    }
}

image-20210307175801948

现在想要给静态代理的案例B也应用这个,我们就还需要修改InvocationHandlerProxy类,这个修改无关紧要,因为他与我们程序本身业务没有关联,可以做到无侵入式编程,为了这个类更加的同样,我们可以把那个代理接口直接编程object类,修改后代码如下

/**
 * @author PengHuAnZhi
 * @createTime 2021/3/7 17:42
 * @projectName DesignPrinciples
 * @className InvocationHandlerProxy.java
 * @description TODO
 */
@Data
public class InvocationHandlerProxy implements InvocationHandler {
    //被代理的接口
    private Object object;

    //生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        //动态代理的本质就是使用反射机制实现
        return method.invoke(object, args);
    }

    public void log(String methodName) {
        System.out.println("调用了" + methodName + "方法");
    }
}

再次测试

public static void main(String[] args) {
    UserServiceImpl userService = new UserServiceImpl();
    InvocationHandlerProxy invocationHandlerProxy = new InvocationHandlerProxy();
    invocationHandlerProxy.setObject(userService);
    UserService userServiceProxy = (UserService) invocationHandlerProxy.getProxy();
    userServiceProxy.add();
    userServiceProxy.delete();
    userServiceProxy.update();
    userServiceProxy.query();
}

image-20210307180808292

动态代理代理的就是一个接口,接口下的一系列业务都会被代理,也就是一个动态代理类可以代理很多的类,可以不用再一对一的手动实现代理类

标签:void,Object,代理,模式,System,rent,public
来源: https://blog.csdn.net/qq_43509535/article/details/114492155