设计模式(四):代理模式

前言

国内程序员好像普遍对百度都没好感,而且百度近些年产生了不少负面的新闻,像16年的魏则西事件,近期的导演吴京黑白照事件,以及最近作家六六斥百度李彦宏:“你是做搜索引擎还是骗子首领”,还有一件就是与程序员有关的:搜索Julia语言,在百度和Google得出首条搜索结果的差异性而被吐槽。Google虽然受欢迎,但是在国内因内容审查问题未解决而不能使用,如果我们要使用它就必须使用代理服务器,由于放置代理服务器的地区区域可以访问google,所以我们可以先访问代理服务器,通过代理服务器转发我们的请求。这是现实生活中的一种代理模式的实例,当然现实生活中这种实例很不少,像明星都有助理,打官司有代理律师等等,这种思想也可以用到我们程序设计中。

介绍

在设计模式中代理模式可以分为静态代理动态代理,而动态代理根据代理的对象类型不同又可以分为Jdk动态代理Cglib动态代理
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。

实现

近几年中国电影行业蓬勃发展,电影摄制需要的一种特殊演员->替身,主要任务是代替影片中原演员表演某些特殊的、高难度的动作和技能或原演员所不能胜任的惊险动作,如武打、骑术、驾车等。拍摄的时候虽然是替身在拍摄,但是呈现在荧幕前我们观众却不知道是替身而认为是明星的真实拍摄,代理模式也有这种特点,虽然是代理类在完成任务,但是呈现出来的却是真实类的实现。接下来我们以这种生活中的实例来作示例:

公共表演接口的定义

/** 表演 */
public interface Performance {
    void act();
}

一.静态代理

明星的实体类

/** 明星 */
public class Actor implements Performance {
    @Override
    public void act() {
        System.out.println("明星上场拍功夫电影");
    }
}

替身演员的实体类

/**
 * 替身演员
 */
public class Stuntman implements Performance {

    private Actor actor;

    @Override
    public void act() {
        if (actor == null) {
            actor = new Actor();
        }
        System.out.println("替身演员表演跳火车.");
        actor.act();
        System.out.println("替身演员表演空中360°旋转飞踢.");
    }
}

执行Demo

public class ProxyPatternDemo {
    public static void main(String[] args) {
        System.out.println("------电影拍摄开始------");
        Performance perform = new Stuntman();
        perform.act();
        System.out.println("------电影拍摄结束------");
    }
}

执行程序,输出结果:

------电影拍摄开始------
替身演员表演跳火车.
明星上场拍功夫电影
替身演员表演空中360°旋转飞踢.
------电影拍摄结束------

二.Jdk动态代理

1、Jdk动态代理是由Java内部的反射机制来实现的,目标类基于统一的接口InvocationHandler
2、代理对象是在程序运行时产生的,而不是编译期;
3、对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;之后我们通过某种方式执行真正的方法体,
4、对于从Object中继承的方法,JDK动态代理会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发。详见JDK Proxy官方文档

jdk动态代理实现

public class JdkDynamicProxy implements InvocationHandler {

    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("替身演员表演跳火车.");
        Object o = method.invoke(target, args);
        System.out.println("替身演员表演空中360°旋转飞踢.");
        return o;
    }

    public Object bind(Object target) {
        //取得代理对象
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

执行Demo

public static void main(String[] args) {
     //创建JDK动态代理类
     JdkDynamicProxy proxy = new JdkDynamicProxy();
     //绑定对象
     Performance performProxy = (Performance) proxy.bind(new Actor());
     System.out.println("------电影拍摄开始------");
     performProxy.act();
     System.out.println("------电影拍摄结束------");
}

执行结果

------电影拍摄开始------
替身演员表演跳火车.
明星上场拍功夫电影
替身演员表演空中360°旋转飞踢.
------电影拍摄结束------

Java动态代理为我们提供了非常灵活的代理机制,但Jdk动态代理是基于接口的,如果对象没有实现接口我们该如何代理呢?答案是Cglib动态代理。

三.Cglib动态代理

cglib动态代理底层则是借助asm来实现的,它允许我们在运行时对字节码进行修改和动态生成,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
目标类基于统一的接口MethodInterceptor

CGLIB的核心类
net.sf.cglib.proxy.Enhancer – 主要的增强类。
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现。
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。

我们要使用cglib代理必须引入cglib的jar包(package net.sf.cglib.proxy;),我在这里使用的是spring包中cglib,其实和单独的引cglib包是一样的,只不过spring为了版本不冲突,将cglib包含在自己的包中。

cglib动态代理实现:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibDynamicProxy implements MethodInterceptor {

    private Object target;

    //创建代理对象
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("替身演员表演跳火车.");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("替身演员表演空中360°旋转飞踢.");
        return result;
    }
}

执行Demo

public static void main(String[] args) {
       CglibDynamicProxy cglibProxy = new CglibDynamicProxy();
        Performance userService = (Performance) cglibProxy.getInstance(new Actor());
        System.out.println("------电影拍摄开始------");
        userService.act();
        System.out.println("------电影拍摄结束------");
    }

执行结果

------电影拍摄开始------
替身演员表演跳火车.
明星上场拍功夫电影
替身演员表演空中360°旋转飞踢.
------电影拍摄结束------

总结

1、通过以上的例子我们可以发现代理模式的特点:
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

2、Jdk动态代理和Cglib动态代理的区别:

  • JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
  • cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。同样的,final方法是不能重载的,所以也不能通过CGLIB代理,遇到这种情况不会抛异常,而是会跳过final方法只代理其他方法。
  • JDK动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。
  • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
  • 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

原文地址:https://www.cnblogs.com/jajian/p/9691221.html

时间: 2024-08-02 21:52:05

设计模式(四):代理模式的相关文章

设计模式<四>——代理模式

番外:仅供个人学习 类图: 客户想要操作RealSubject,但实际上是操作Proxy,然后让Proxy去代理客户操作RealSubject.继承统一接口的好处是使得代理类(Proxy)和被代理类(RealSubject)对外都暴露统一的接口.实际上,视情况而定,不一定非得继承至统一接口. 与适配器模式的区别:适配器模式着重于数据的转化适配,而代理模式着重于操作的转移

【设计模式】代理模式

代理模式在所需对象和用户代码之间增加了一层对象,这个对象被称为代理.用户代码只需要直接操作代理对象即可.著名的代理模式的例子就是引用计数指针对象,它使得我们对真实对象的操作都需要经过引用计数指针对象.下面是用C++写的一个运用了代理模式的例子. #include <iostream> #include <string> using namespace std; // 作为接口的抽象基类 class Subject { public: virtual void DoAction()

设计模式之代理模式 c++实现以及详解

proxy模式 <1> 作用: 为其他对象提供一种代理以控制对这个对象的访问. <2> 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1.修改原有的方法来适应.这样违反了"对扩展开放,对修改关闭"的原则. 2.就是采用一个代理类调用原有的方法,且对产生的结果进行控制.这种方法就是代理模式. 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! <3> 结构图 代理类,含有一个指向RealSubject

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类

设计模式之代理模式20170724

结构型设计模式之代理模式: 一.含义 代理模式也叫做委托模式,其定义如下: 为其他对象提供一种代理以控制对这个对象的访问. 二.代码说明 1.主要有两个角色 1)具体主题角色 也叫做委托角色.被代理角色.它是业务逻辑的具体执行者. 2)代理主题角色 也叫做委托类.代理类.它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作. 一个代理类可以代理多个被委托者或被代理者. 2.在用C实现过程中也是参考这种思想,以游戏代理场

设计模式三: 代理模式(Proxy) -- JDK的实现方式

设计模式三: 代理模式(Proxy) -- JDK的实现方式 简介 代理模式属于行为型模式的一种, 控制对其他对象的访问, 起到中介作用. 代理模式核心角色: 真实角色,代理角色; 按实现方式不同分为静态代理和动态代理两种; 意图 控制对其它对象的访问. 类图 实现 JDK自带了Proxy的实现, 下面我们先使用JDK的API来演示代理如何使用, 随后再探究Proxy的实现原理,并自己来实现Proxy. JDK代理类的使用: (InvocationHandler,Proxy) 使用JDK实现的代

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

【大话设计模式】——代理模式

对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念.Hibernate 的继承映射可以理解持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到. Hibernate支持三种继承映射策略: 使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态. 使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表

JAVA设计模式(3)----代理模式

1.  什么是代理模式?Proxy Pattern 代理模式定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 通俗的讲,代理模式就是我很忙没空理你,你要想找我可以先找我的代理人,代理人和被代理人继承同一个接口.代理人虽然不能干活,但是被代理的人可以干活. 这个例子中有水浒传中的这么几个人:名垂青史的潘金莲,王婆,西门大官人.西门庆想要找潘金莲,需要找王婆做代理.首先定义一个接口:Kin