设计模式之代理模式

来源:互联网 发布:管理者心态管理知乎 编辑:程序博客网 时间:2024/06/12 00:12

代理模式在我们生活中是十分常见的,例如,帮我打包午饭,帮我拿一下快递,这些是我们日常的代理模式。其中你是委托人,代理人是你朋友,而事件就是打包午饭、拿快递。

简介

代理模式的定义:Provide a surrogate or placeholder for another object to controlaccess to it(为其他对象提供一种代理以控制对这个对象的访问)。

模式中的角色与职责

Subject: 抽象主题类
  该类的主要职责是申明真是主题与代理的共同接口方法,该类既可以是个抽象类也可以是个接口(具有抽象方法)。
  
RealSubject: 真实主题类
  该类也称为委托类或者被代理类,该类定义了代理所表示的真是对象(也就是实现了抽象方法),由其执行具体的业务逻辑。
  
ProxySubject:代理类
  这个类的对象持有一个对真实主题的引用,在这个类所实现的接口方法中调用真实主题类中相应的方法执行,这样就实现了代理的目的。
  
Client:客户类
  也就是使用代理类的类型,客户类通过代理类间接地调用了真实主题类中定义的方法。

代理模式可以分为静态代理和动态代理。

静态代理

具体实现代码如下:

public class JavaDemo {    public static void main(String[] args) {        ProxySubject proxySubject = new ProxySubject(new RealSubject());        proxySubject.request();    }}interface Subject {    abstract void request();}class RealSubject implements Subject {    @Override    public void request() {        // TODO Auto-generated method stub        System.out.println("To do something.");    }}class ProxySubject implements Subject {    private RealSubject mRealSubject;    public ProxySubject(RealSubject realSubject) {        super();        // TODO Auto-generated constructor stub        mRealSubject = realSubject;    }    @Override    public void request() {        // TODO Auto-generated method stub        mRealSubject.request();    }}

通过示例代码相信大家对静态代理有了一定的理解。
1.委托人和代理人都可以完成同样一件事。(实现同一个接口)
2.委托人告诉代理人去完成这件事,代理人才去做这件事。(代理人需要持有委托人引用)

动态代理

同样是带午饭的场景,但是自己写代码写到忘记了时间,一抬头发现同事都走光了,那么谁能帮自己带个饭呢?在等待的过程中是谁先出现,张三还是李四?(程序需要动态创建一个对象)而且最重要的是出现的那个同事要能帮自己带饭才行(上步创建的对象需要实现Subject接口)

public class JavaDemo {    public static void main(String[] args) {        final Subject realSubject = new RealSubject();        //第一个参数,目标的装载器          //第二个参数,目标接口,为每个接口生成代理          //第三个参数,实现了InvocationHandler接口,当你一调用代理,代理就会调用InvocationHandler的invoke方法          Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),                realSubject.getClass().getInterfaces(), new InvocationHandler() {                    @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        // TODO Auto-generated method stub                        //调用目标方法                         return method.invoke(realSubject, args);                    }                });        subject.request();    }}interface Subject {    abstract void request();}class RealSubject implements Subject {    @Override    public void request() {        // TODO Auto-generated method stub        System.out.println("To do something.");    }}

InvocationHandler相当于一个处理器,在invoke方法中我们能够操作真实对象,可以附加其他操作。而我们通过Proxy.newProxyInstance(..)方法生成代理。实现InvocationHandler接口并附加操作后,获取代理角色。

动态代理的重点在于Proxy.newProxyInstance(),有兴趣的同学可以看看里面的实现源码。主要步骤是:
1.ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复杂,有兴趣的同学可以继续分析源码 sun.misc.ProxyGenerator;
2.native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。
3.利用clazz.newInstance反射机制生成代理类的对象;

而动态代理是相当强大的,下面我们自己看一下Retrofit的动态代理例子:

Retrofit是现在最火的Android网络请求框架之一,相信大家或多或少都有了解过。我们看一下Retrofit怎么使用动态代理模式的。

1.创建一个请求方法的接口:

public interface HttpService {    @FormUrlEncoded    @POST(URLs.Login)    Call<JSONObject> login(@FieldMap() Map<String, String> maps);}

2.生成Retrofit对象,并且创建一个实现了GitHubServiece接口的实体类:

Retrofit retrofit = new Retrofit.Builder()    .baseUrl(BASE_URL)    .build();HttpService mHttpService = retrofit.create(HttpService.class);

上面的大家用过Retrofit都会很熟悉,我们看一下create()的代码:

  public <T> T create(final Class<T> service) {    Utils.validateServiceInterface(service);    if (validateEagerly) {      eagerlyValidateMethods(service);    }    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },        new InvocationHandler() {          private final Platform platform = Platform.get();          @Override public Object invoke(Object proxy, Method method, Object... args)              throws Throwable {            // If the method is a method from Object then defer to normal invocation.            if (method.getDeclaringClass() == Object.class) {              return method.invoke(this, args);            }            if (platform.isDefaultMethod(method)) {              return platform.invokeDefaultMethod(method, service, proxy, args);            }            ServiceMethod serviceMethod = loadServiceMethod(method);            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });  }

经过上面对动态代理的理解,对create()封装的代码,一看就非常清楚,就是动态代理模式嘛。


了解了静态代理和动态代理可能大家会想,在代码层面上本来就可以自己完成,为什么要交给其他类完成呢?这样不是多此一举吗?但在实际开发中,使用代理模式的作用有:

  • 解耦:这是设计模式解决的基本问题。在这里委托类只需要做好自己的部分工作,然而一些额外的事情可以交给代理类完成。如自己准备结婚,但是不可能自己去一手一脚去准备整个婚礼,我们自己只需要请婚庆公司,定好价钱然后婚庆公司就能帮我们解决整场婚礼的大小事,我们自己不需要婚庆公司怎么完成,这样是不是将我与结婚事件进行了解耦。

  • 拦截、扩展:代理类在实现接口方法的时候,除了调用委托类方法外,还可以在不修改委托类的情况下,增加一些其他需求功能。如我们试想在实现类满足要求时,我们可以直接使用实现类,但是实现类再满足不了需求的时候,我们就得扩展,但是根据开闭原则,我们不能直接修改实现类的代码,这样我们可以通过代理类可扩展功能;另外就是我们权限分配,我们可以根据对申请权限的对象进行拦截,根据不同的角色条件做判断,然后再分配对用的权限。

0 0
原创粉丝点击