代理模式

目录

 

一、代理模式的介绍

1、定义

2、使用场景

3、优缺点

(1)优点

(2)缺点

二、代理模式的实现

1、静态代理

(1)场景描述

(2)实现过程

(3)总结

2、动态代理

(1)介绍

(2)实现方式

(3)总结

三、与其他模式的比较

1、装饰器模式与代理模式

2、适配器模式与代理模式

3、外观模式与代理模式


一、代理模式的介绍

1、定义

       代理模式为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式在我们的生活中十分常见,如:买东西找代购。

       代理模式的角色划分:

  • 抽象主题角色(Subject):该角色是真实主题和代理主题的共同接口,以便在任何可以使用真实主题的地方都可以使用代理主题。
  • 代理主题角色(Proxy Subject):也叫做委托类、代理类。该角色负责控制对真实主题的引用,负责在需要的时候创建或删除真实主题对象,并且在真实主题角色处理完毕前后做预处理和善后的工作。
  • 真实主题角色(Real Subject):该角色也被称为被委托角色、被代理角色,是业务逻辑的具体执行者。

       代理模式的类图如下:

2、使用场景

  • 远程代理:为一个位于不同的地址空间的对象提供一个全局代表对象。这个不同的地址空间可以是在本机器中,也可以是在另外一台机器中。
  • 虚拟代理:有时需要创建一些消耗较多资源的对象,可以首先创建代理对象,而将真实对象的创建延迟。例如:加载一个很大的图片,可以通过图片的代理来代替真正的图片。
  • 保护代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
  • 缓存代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  • 同步代理:使几个用户能够同时使用一个对象而没有冲突。
  • 智能引用代理:当一个对象被引用时,提供一些额外的操作,例如:记录访问流量和次数等。

3、优缺点

(1)优点

  • 职责清晰:真是的角色实现实际的业务逻辑,不用关系其他非本职的事务,通过后期的代理完成附加的事务,附带的结果就是编程简洁清晰。
  • 高扩展性:具体主题角色随需求不同可能有很多种,但只要实现了接口,代理类就完全可以在不做任何修改的情况下代理各种真实主题角色。
  • 智能化:代理类可以在运行时才确定需要去代理的真实主题。

(2)缺点

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

二、代理模式的实现

1、静态代理

(1)场景描述

       有一天,跟随你多年的小伙伴——你心爱的电脑终于走到了生命的终结点。于是,你打算购买一台新电脑。精挑细选之后,你相中了联想小新。但是工作了一天的劳累使你不想再去电脑城,于是,你找了一个代理帮你去购买电脑,然后送到家。其UML如下:

(2)实现过程

       主题类:IComputer

/**
 * 抽象主题类
 */
public interface IComputer {
    /**
     * 买电脑
     */
    void buyComputer();
}

       代理主题类:

/**
 * 代理主题类
 */
public class PorxySubject implements IComputer{
    private IComputer computer;

    public PorxySubject(IComputer computer) {
        this.computer = computer;
    }

    /**
     * 买电脑。在买电脑的前后,代理可以做一些其他的事情。而这些事情,真实主题类并不在乎。
     */
    @Override
    public void buyComputer() {
        this.before();
        computer.buyComputer();
        this.after();
    }

    /**
     * 买电脑之后
     */
    private void after() {
        System.out.println("联想售后:忠心陪伴每一位客户");
    }

    /**
     * 买电脑之前
     */
    private void before() {
        System.out.println("联想店离我很远,但我仍然要去。不为别的,只因为我是代理。虽然辛苦,但我尽职尽责。");
    }
}

        真实主题类:

/**
 * 真实主题类
 */
public class RealSubject implements IComputer{

    @Override
    public void buyComputer() {
        System.out.println("联想小新");
    }
}

       测试类:

public class Client {
    public static void main(String[] args) {
        IComputer computer = new PorxySubject(new RealSubject());
        computer.buyComputer();
    }
}

        执行结果如下:

(3)总结

       静态代理的优点在于:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展。但由于代理对象需要与目标对象实现一样的接口,所以会有很多的代理类。

       静态代理的缺点:由于真实主题类和代理主题类实现了相同的接口,代理主题类通过真实主题类实现了相同的方法,这样就会出现大量的代码重复。如果在主题类中增加一个新的方法,那么不仅真实主题类需要实现新方法,代理类也需要实现该方法,增加了代码维护的复杂度。此外,如果代理模式需要服务多类型的对象,那么就要为每一种对象都进行代理,此时的静态代理就无法胜任了。这就需要使用动态代理的方式来完成。

2、动态代理

(1)介绍

       在静态代理中,每个代理类只能为一个接口服务,如果需要有多个服务,就会产生很多的代理类。所以我们就可以用动态代理的方式用一个代理类完成全部的代理功能。动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。

(2)实现方式

       场景与静态代理一致,我们来看看动态代理的实现方式。这里,主题类和真实主题类保持不变,只需要实现了动态处理器类即可,如下:

public class DynamicProxyHandler implements InvocationHandler {
    private Object object;

    public DynamicProxyHandler(Object object) {
        this.object = object;
    }

    /**
     * 买电脑之后
     */
    private void after() {
        System.out.println("联想售后:忠心陪伴每一位客户");
    }

    /**
     * 买电脑之前
     */
    private void before() {
        System.out.println("联想店离我很远,但我仍然要去。不为别的,只因为我是代理。虽然辛苦,但我尽职尽责。");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.before();
        Object result = method.invoke(object, args);
        this.after();
        return result;
    }
}

       测试类如下:

public class Client {
    public static void main(String[] args) {
        IComputer computer = new ComputerImpl();
        IComputer c = (IComputer) Proxy.newProxyInstance(IComputer.class.getClassLoader(), new Class[]{IComputer.class}, new DynamicProxyHandler(computer));
        c.buyComputer();
    }
}

这里介绍一下Proxy.newProxyInstance()方法的三个参数:

  • ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的。
  • Class<?>[] interfaces:指定目标对象实现的接口类型,使用泛型方式确定类型。
  • InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法。

(3)总结

       相比于静态代理,动态代理最大的好处就是接口中所声明的所有方法都被转移到调用处理器的一个集中的方法中进行处理。当接口方法数量比较多的时候,不再像静态代理那样对每一个方法进行中转。

三、与其他模式的比较

1、装饰器模式与代理模式

       装饰器模式关注于对一个对象动态的添加方法,可以将原始对象作为一个参数传给装饰者的装饰器,可以不停递归下去,就好比你要邮寄一个易碎的杯子,加了一层包装你不放心,于是你加了一层又一层(循环套娃)。
代理模式则侧重于对对象的访问控制,代理类能够对它的客户隐藏一个对象的具体信息。

2、适配器模式与代理模式

       适配器模式为它所适配的对象提供了一个不同的接口,能够改变对象的接口。而代理模式做不到

3、外观模式与代理模式

       代理对象代表的是一个单一的对象,而外观对象则代表的是一个子系统。

       代理的客户对象无法直接访问对象,由代理类提供对目标对象的访问。而外观对象提供对子系统中各元件功能的简化的共同层次的调用接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值