设计模式之代理模式

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

简介

代理模式的定义: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()封装的代码,一看就非常清楚,就是动态代理模式嘛。


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

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

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

代理模式是一种结构型设计模式,它提供一个代理对象来代表另一个对象。在代理模式中,有一个被称为实际对象(Subject)和一个被称为代理对象(Proxy)的中介,代理对象持有实际对象的引用,并且可以控制对实际对象的访问。代理模式的主要目的是在不修改原始对象的情况下,为原始对象添加额外的逻辑处理。 代理模式分为多种类型,如远程代理、虚拟代理、保护代理等,它们各自有不同的应用场景: - 远程代理:为远程对象提供一个本地代表。 - 虚拟代理:根据需要创建开销大的对象,通过虚拟代理控制访问这些对象的过程。 - 保护代理:控制对原始对象的访问权限,例如进行权限检查。 代理模式的优点包括: 1. 能够控制对真实对象的访问,并在访问前后添加额外的逻辑。 2. 可以通过代理对象实现延迟加载,即在实际需要时才创建真实对象。 3. 增强了对真实对象的封装,并且可以避免对真实对象的重复引用。 在C#中实现代理模式通常涉及以下步骤: 1. 定义一个接口或抽象类,声明真实对象和代理对象需要实现的方法。 2. 实现真实对象的类,按照接口或抽象类的要求实现具体方法。 3. 实现代理类,它同样实现接口或抽象类,并在方法中持有真实对象的引用,通过调用真实对象的方法来执行所需的操作,同时可以添加额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值