设计模式——代理模式

所谓代理模式,就相当于我们生活中的代理一样,比如说,我们要去租赁一个房子,直接找房东是不容易的,一般我们会找一个中介,也就是代理,来租房子,这个中介不仅能把房东的房子租给我们,而且可以带我们看房子等操作

当我们完成一个租房这件事时,实际上需要参与的有三个人,分别是租房者、中介和房东

静态代理

通过静态代理我们来实现中通过中介来出租房子,这里首先定一个出租房子的接口

package com.zhiying.demo01;

public interface Rent {
    public void rent();
}

然后房东来实现这个接口

package com.zhiying.demo01;

public class Host implements Rent {
    public void rent() {
        System.out.println("房东出租房子");
    }
}

中介也就是代理也要实现这个接口,主要是来棒房东出租房子

package com.zhiying.demo01;

public class Proxy implements Rent{
    private Host host;

    public void setHost(Host host) {
        this.host = host;
    }

    public void rent() {
        //这里是代理帮助房东出租房子
        host.rent();
    }

}

然后是客户类

package com.zhiying.demo01;

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

客户通过代理租到了房子,这样做的好处是,当我们有新的工作要做的时候,我们只要找代理就可以了,而无须找房东,假如我们这里新增看房子和签合同的事情,这里只需代理完成即可,房东还只是出租房子。这里给出修改后的代理类,其他的不变

package com.zhiying.demo01;

public class Proxy implements Rent{
    private Host host;

    public void setHost(Host host) {
        this.host = host;
    }

    public void rent() {
        //这里是代理帮助房东出租房子
        host.rent();
        seeHost();
        seeHost();
    }

    public void seeHost() {
        System.out.println("代理带你看房子");
    }

    public void signContract() {
        System.out.println("代理跟你签合同");
    }

}

再来一个例子进行深刻理解代理模式,这里以完成CRUD业务来讲解,通过代理进行业务的扩展案例,首先是正常的业务,也就是单纯的CRUD,并且是没有代理的情况

业务的接口

package com.zhiying.demo02;

public interface Service {
    public void add();
    public void delete();
    public void update();
    public void select();
}

业务的实现 

package com.zhiying.demo02;

import javax.xml.bind.SchemaOutputResolver;

public class ServiceImpl implements Service {
    public void add() {
        System.out.println("add");
    }

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

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

    public void select() {
        System.out.println("select");
    }
}

 客户端

package com.zhiying.demo02;

public class Client {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        service.add();
        service.delete();
        service.update();
        service.select();
    }
}

这样是没有任何问题的,但是当我们进行扩展的时候,就需要代理来完成了,假如我们想要在每次执行CRUD之前,输出一个log,由于我们不能改原有的代码,这也符合开闭原则,引入代理

这里新增一个代理类

package com.zhiying.demo02;

public class Proxy implements Service {
    ServiceImpl service;

    public void setService(ServiceImpl service) {
        this.service = service;
    }

    public void add() {
        log("add");
        service.add();
    }

    public void delete() {
        log("delete");
        service.delete();
    }

    public void update() {
        log("update");
        service.update();
    }

    public void select() {
        log("select");
        service.select();
    }

    public void log(String msg) {
        System.out.println("this is " + msg);
    }
}

 客户端类在调用的时候直接调用代理类,其他类不用动

package com.zhiying.demo02;

public class Client {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        Proxy proxy = new Proxy();
        proxy.setService(service);

        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.select();
    }
}

小结:代理模式可以使真实角色(房东)的工作更加纯粹,不用去关注一些公共的业务,公共的业务交给代理来做,实现了业务分工,公共业务发生扩展的时候,方便集中管理。

缺点:每一个真是的角色都会产生一个代理角色,代码量会翻倍,开发效率会降低

为解决这一问题,引入了动态代理,其中动态代理分为两大类,其一是基于接口的JDK提供,其二是基于类的cglib,这里讲解基于接口的

动态代理

JDK提供的类需要了解这两个,分别是,Proxy:代理    InvocationHandler:调用处理程序,同样的我们以租房子为例

出租房子接口

package com.zhiying.demo03;

public interface Rent {
    public void rent();
}

房东类

package com.zhiying.demo03;

public class Host implements Rent {
    public void rent() {
        System.out.println("房东出租房子");
    }
}

动态生成代理类

package com.zhiying.demo03;

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

//该类会自动生成代理类
public class ProxyInvocationHandler 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);
    }

    //处理代理程序,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质,用反射机制
        seeHost();//被扩展的功能可以直接加到这
        Object result = method.invoke(rent,args);
        return result;
    }

    //在这里可以扩展功能
    public void seeHost() {
        System.out.println("代理带看房子");
    }
}

客户类 

package com.zhiying.demo03;

import com.sun.org.apache.regexp.internal.RE;

public class Client {
    public static void main(String[] args) {

        //这是真实角色,也就是我们的房东
        Host host = new Host();

        //创建代理调用处理角色
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();

        //通过调用程序处理角色来处理我们要调用的接口对象
        proxyInvocationHandler.setRent(host);

        //创建代理对象
        Rent proxy = (Rent) proxyInvocationHandler.getProxy();
        proxy.rent();

    }
}

CRUD业务用动态代理实现

首先是业务接口

package com.zhiying.demo04;

public interface Service {
    public void add();
    public void delete();
    public void update();
    public void select();
}

然后是接口的实现

package com.zhiying.demo04;

public class ServiceImpl implements Service {
    public void add() {
        System.out.println("add");
    }

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

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

    public void select() {
        System.out.println("select");
    }
}

然后是动态生成代理类

package com.zhiying.demo04;

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

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

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

    //处理代理类,返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());//调用扩展业务
        Object result = method.invoke(service,args);
        return result;
    }

    //增加的扩展业务
    public void log(String msg) {
        System.out.println("this is " + msg);
    }
}

最后是我们的客户

package com.zhiying.demo04;

public class Client {
    public static void main(String[] args) {
        //创建真实角色,也就是我们的业务
        ServiceImpl service = new ServiceImpl();

        //创建代理调用处理角色
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();

        //设置要代理的对象
        proxyInvocationHandler.setService(service);

        //动态生成代理类
        Service proxy = (Service) proxyInvocationHandler.getProxy();
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.select();
    }
}

总结动态代理类的好处:首先有静态代理类的全部好处

代理模式可以使真实角色(房东)的工作更加纯粹,不用去关注一些公共的业务

公共的业务交给代理来做,实现了业务分工

公共业务发生扩展的时候,方便集中管理

一个动态代理类代理的是一个接口,一般就是对应一类的业务

一个动态代理类可以代理多个类,只要实现了同一个接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贺志营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值