设计模式-代理模式

来源:互联网 发布:本子知乎 编辑:程序博客网 时间:2024/05/16 06:43

代理模式有三个主体,代理,委托代理,具体实例。

它最大的作用就是做到了代理和具体实例的解耦,让代理与具体实例之间没有直接关系。


举个栗子:

最近刚好ipx出来,你高高兴兴的买了回来,刚买好回到家没想到一不小心就掉地上,碎屏了,那当然不开心了,找到专卖店去必须让他们维修。因为你知道专卖店是可以搞定这个事情的,具体是给你换一个呢还是修一下呢,你不知道也不用清楚。第二天来拿果然是好了,美滋滋的回家。

站在专卖店角度来看这件事情,有个倒霉顾客,刚买了ipx第一天就坏了,来要求保修,于是,我们接受了顾客的要求。然后把这个手机交给有合作关系的第三方专业维修机构。

维修好之后,记录该顾客的维修记录。

站在专业维修机构来说,ipx发售第一天就有个倒霉蛋买了ipx就坏了,那么,我们就维修手机。好了之后就给专卖店送过去。

上面的例子中,顾客就是代理人,专卖店就是手里委托代理的中间人,而维修机构就是具体的实例(修手机这件事情)。、


代理模式是面向接口的,对于上面的例子,三者共同关注的是修手机这件事情,于是修手机很自然的就可以被抽象出来。

代码结构结构就是下面这样的。


public interface Service {    //修手机这件事情    void service(Phone phone);}

public class Phone {    //表示手机状态    private boolean status = true;    public boolean isStatus() {        return status;    }    public void setStatus(boolean status) {        this.status = status;    }}

/** * 专卖店 * * Created by Max on 2017/9/25. */public class AppleStore implements Service{    //记录真正维修手机的维修机构。    Service service;    public AppleStore(Service service) {        this.service = service;    }    //专卖店的service可以看做是接受了客户的维修委托。    @Override    public void service(Phone phone) {        System.out.println("======把手机送到维修机构中...");        service.service(phone);        System.out.println("======手机维修好了,记录客户的维修记录...");    }}

/** * 专业维修机构 * * Created by Max on 2017/9/25. */public class PhoneService implements Service {    @Override    public void service(Phone phone) {        System.out.println("维修机构拿到了手机...");        //维修手机        phone.setStatus(true);        System.out.println("手机修好了...");    }}

Phone phone = new Phone();        //手机坏了。        phone.setStatus(false);        AppleStore appleStore = new AppleStore(new PhoneService());        //将手机送到专卖店中去。        appleStore.service(phone);        System.out.println("客户拿到的手机.."+phone.isStatus());

输出:

======把手机送到维修机构中...
维修机构拿到了手机...
手机修好了...
======手机维修好了,记录客户的维修记录...
客户拿到的手机..true


客户并不知道维修机构的存在(或者说明面上它找的是专卖店),而维修机构也不知道手机的主人是谁,一切的关键就在于受理委托代理的专卖店。是专卖店在中间起到了桥接联系的作用。

这就是代理模式,而且是代理模式中的静态代理模式。


虽然解耦是代理静态代理的优点,但是缺点也是非常明显的,那就是如果这时候顾客想要把手机壳换成蓝色的,那么势必,service服务必然是要增加换手机壳的方法,专卖店和维修机构必然也是对于换壳这件事情做出反应。那么代码的维护以及复杂度就会增加。


而动态代理可以解决这件事情。



我们看上面这张图,可以分析一下,修手机这件事情只有具体实例永远知道如何修手机,他是必要条件。

而中间的代理,只是接受委托,代理了修手机这件事情,换一个说法,在北京的苹果专卖店可以接受修手机的委托,那么上海的苹果专卖店为什么不可以呢?

因为并非是必要的,也就是说他是可以被替换的。

而专卖店难道就可以接受修手机的方法,肯定是可以接受很多委托代理的(类比各种售后。。)

这么一来的中间的受理的代理者就不再是死的了。

看过银魂的都知道,阿银他们的开的是万事屋,也就是接受任何委托,那么我很好奇啊,如果我让他们接受修手机这件事情他们接不接受啊。

答案当然是可以的了,因为代理任何事情,这就是所以的动态。

java中,这种动态创建代理底层是由反射来做的。

因此,动态代理的两个核心类,都在

java.lang.reflect

反射包下。

InvocationHandler

该接口只有一个invoke,当代理对外的一切方法(专卖店对外公布修手机方法)被调用时,注意,我说的是一切方法被调用!!代理内部(专卖店)就会调用invoke方法,而我们则调用具体的实例(维修机构)来处理具体的业务逻辑(修手机)。

因此我们的代码是这样的。

public class DynamicProxy implements InvocationHandler {    //真正的业务逻辑实现类    private Object object;    public DynamicProxy(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object result = null;        System.out.println("我是动态代理...");        result = method.invoke(object,args);        System.out.println("动态代理已完成...");        return result;    }}

invocationHandler接口可以简单的看成替换了上面例子的Service接口,所有对外公布的方法(接口中的方法),都会转发到invoke这里。

来看看invoke方法参数的三个参数:

1.代理实例,可以理解为对外公布的规范。

2.代理实例有那么多方法,到底调用在转到处理这边时将会具体化成java中的反射的Method对象,method.invoke可以直接执行方法,参数为具体要操作的对象。(也就是Object)。

3.调用方法的参数。

Proxy

类。

DynamicProxy并非是动态代理,它只是动态代理被调用的后续处理。

Phone phone = new Phone();        //手机坏了。        phone.setStatus(false);        DynamicProxy dynamicProxy = new DynamicProxy(new PhoneService());        //创建动态代理        Service service = (Service)Proxy.newProxyInstance(                DynamicProxy.class.getClassLoader(),                new Class[]{ Service.class },                dynamicProxy        );        service.service(phone);

上面

Proxy.newProxyInstance

才是创建了一个真正的动态代理。

该方法有三个参数,分别是:

1.动态代理类加载器

2.需要实现的接口方法列表。

3.动态代理方法被调用的后续处理程序。

方法返回一个动态代理类,该类可以调用所有参数二中的方法,调用任意一个方法后都会转发给参数三的实例。

简单理解就是你去万事屋说  我要修手机,那么万事屋也是对你说  我要修手机

ni.我要修手机(),

wanshiwu.我要修手机.


上面的测试代码输出:

我是动态代理...
维修机构拿到了手机...
手机修好了...
动态代理已完成...


不好理解的看图说话。


图中不管是A方法还是B方法在invoke都是method。

看图也能看出,第一张图和第二张图最大的不同就是中间的代理整个都换掉了,并且动态代理徐只要实现java提供给我们的类,不需要在去实现每个集体的业务接口。

又大大的把程序的工作细化以及分割。

最后看下代理的小例子代码:

public class DynamicProxy implements InvocationHandler {    //真正的业务逻辑实现类    private Object object;    public DynamicProxy(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object result = null;        System.out.println("我是动态代理...");        result = method.invoke(object,args);        System.out.println("动态代理已完成...");        return result;    }}


public class UserImpl implements User {    @Override    public void study() {        System.out.println("我是  "+this.getClass().getInterfaces()[0].getName()+"  具体的实现类...........");        System.out.println("study..............");    }    @Override    public int study(String str) {        int a = 2;        System.out.println("今天学习  " +str);        return a;    }}

public interface Worker {    void work();}
public class WorkerImpl implements Worker {    @Override    public void work() {        System.out.println("我是  "+this.getClass().getInterfaces()[0].getName()+"  具体的业务实现逻辑...");        System.out.println("worker...");    }}


 //动态代理模式        DynamicProxy userDynamicProxy = new DynamicProxy(new UserImpl());        User user = (User)Proxy.newProxyInstance(                DynamicProxy.class.getClassLoader(),                new Class[]{User.class},                userDynamicProxy        );        user.study();        String string = "语文";        int a = user.study(string);        System.out.println("今天学习语文学习了  "+a+"  个小时");        System.out.println("======================我是分割线==========================");        DynamicProxy workerDynamicProxy = new DynamicProxy(new WorkerImpl());        Worker worker = (Worker)Proxy.newProxyInstance(                DynamicProxy.class.getClassLoader(),                new Class[]{Worker.class},                workerDynamicProxy        );        worker.work();


输出:

我是动态代理...
我是  User  具体的实现类...........
study..............
动态代理已完成...
我是动态代理...
今天学习  语文
动态代理已完成...
今天学习语文学习了  2  个小时
======================我是分割线==========================
我是动态代理...
我是  Worker  具体的业务实现逻辑...
worker...
动态代理已完成...


参考

https://www.daidingkang.cc/2017/07/18/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/


原创粉丝点击