Java通俗易懂系列设计模式之代理模式

前言

国内程序员好像普遍对百度都没好感,而且百度近些年产生了不少负面的新闻,像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、通过以上的例子我们可以发现代理模式的特点:

优点:

  • 职责清晰。
  • 高扩展性。
  • 智能化。

缺点:

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

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

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

以上就是Java通俗易懂系列设计模式之代理模式的详细内容,更多关于Java设计模式的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java设计模式之代理模式详解

    一.代理模式 代理模式就是有一个张三,别人都没有办法找到他,只有他的秘书可以找到他.那其他人想和张三交互,只能通过他的秘书来进行转达交互.这个秘书就是代理者,他代理张三. 再看看另一个例子:卖房子 卖房子的步骤: 1.找买家 2.谈价钱 3.签合同 4.和房产局签订一些乱七八糟转让协议 一般卖家只在签合同的时候可能出面一下,其他的1,2,4都由中介去做.那你问这样有什么用呢? 首先,一个中介可以代理多个卖房子的卖家,其次,我们可以在不修改卖家的代码的情况下,给他实现房子加价.打广告等等夹带私货的

  • 浅谈JAVA设计模式之代理模式

    代理模式 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能.这种类型的设计模式属于结构型模式. 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口. 介绍 意图: 为其他对象提供一种代理以控制对这个对象的访问. 主要解决: 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时

  • Java简单实现动态代理模式过程解析

    基本知识:JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能生成代理对象. 步骤: 1.首先建一个接口类,并提供一个实现类: public interface ISubject { public int add(int a, int b); } public class Subject implements ISubject { @Override public int add(int a, int b) { return a + b; } } 2.创建一

  • 轻松掌握Java代理模式

    定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 特点: 1.真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰. 2.代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用. 3.扩展性高 企业级开发和常用框架中的应用:最著名的就是spring的aop,还有spring的bea

  • Java代理模式详细解析

    代理模式是我们比较常用的设计模式之一.其中新思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象.这些额外的操作通常需要与实际对象进行通信,代理模式一般涉及到的角色有: 抽象角色:声明真实对象和代理对象的共同接口: 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象.同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装. 真实角色:代理角色所代表的真实对象,

  • 23种设计模式(7) java代理模式

    23种设计模式第七篇:java代理模式 定义: 为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 角色: 1.抽象角色:声明真实对象和代理对象的共同接口. 2.代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象.同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装. 3.真实角色:

  • java代理模式与动态代理模式详解

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费.但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的.这点很重要!

  • Java线程创建静态代理模式代码实例

    一.背景 在通过Runnable接口创建线程时,启动线程需要借助Thread类,这里就涉及到了静态代理模式. 二.实例 以歌手演出为例,在演出的这个过程中,歌手与他的助理他们有一个共同的目标"完成这场演出". 为啥需要歌手需要有助理呢? 因为举办好一场演出有很多繁琐的事情要做,为了让歌手专心完成"唱歌"这件事,助理就需要在背后帮助歌手做很多事情. 1.助理负责帮助歌手做一些辅助工作,例如帮忙宣传.帮忙计划行程.帮忙订机票等等. 2.歌手负责唱歌这件事情. 三.实例的

  • Java代理模式实例分析

    本文实例讲述了Java代理模式.分享给大家供大家参考,具体如下: 一 不用代理模式的酒商 1 代码 class RealSubject // 真实角色(红酒厂商) { public void sell() { System.out.println("我是红酒厂商,欢迎品尝购买"); } } public class NoProxytest { // 客户端 public static void main( String[] args ) { RealSubject sub = new

  • Java代理模式实例详解【静态代理与动态代理】

    本文实例讲述了Java代理模式.分享给大家供大家参考,具体如下: 即Proxy Pattern,23种java常用设计模式之一.代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问. Java的代理模式是Java中比较常用的设计模式,分为2中代理:静态代理与动态代理(JDK动态代理和cglib动态代理) 优点: 职责清晰 真实角色只需关注业务逻辑的实现,非业务逻辑部分,后期通过代理类完成即可. 高扩展性 不管真实角色如何变化,由于接口是固定的,代理类无需做任何改动. 缺点: 很明显的一点

  • Java基础之让你彻底搞懂代理模式

    一.代理模式 什么是代理模式? 先来生活常用例子:你想买票,你没必要去车站买:而是可以去一个代售点,代售点代理车站卖票,这就是一个简单的代理模式! 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层. 总结:我们访问实例对象时是通过代理对象访问的,这样比较灵活也可以添加一些

随机推荐