代码编织梦想

一、代理模式介绍

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

举个例子,我们生活中经常到火车站去买车票,但是人一多的话,就会非常拥挤,于是就有了代售点,我们能从代售点买车票了。这其中就是代理模式的体现,代售点代理了火车站对象,提供购买车票的方法。

二、静态代理

这种代理方式需要代理对象和目标对象实现一样的接口。

优点:可以在不修改目标对象的前提下扩展目标对象的功能。

缺点:

  1. 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
  2. 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。

举例:保存用户功能的静态代理实现

  • 接口类: IUserDao
package com.allen.proxy;

/**
 * @author :jhys
 * @date :Created in 2021/7/16 19:19
 * @Description :
 */
public interface IUserDao {
    public void save();
}
  • 目标对象:UserDao
package com.allen.proxy.impl;

import com.allen.proxy.IUserDao;

/**
 * @author :jhys
 * @date :Created in 2021/7/16 19:20
 * @Description :
 */
public class UserDao implements IUserDao {
    @Override
    public void save() {
        System.out.println("保存数据");
    }
}
  • 静态代理对象:UserDaoProxy 需要实现IUserDao接口!
package com.allen.proxy.impl;

import com.allen.proxy.IUserDao;

/**
 * @author :jhys
 * @date :Created in 2021/7/16 19:20
 * @Description :
 */
public class UserDaoProxy implements IUserDao {

    private IUserDao target;

    public UserDaoProxy(IUserDao target) {
        this.target = target;
    }

    @Override
    public void save() {
        System.out.println("开启事务");
        target.save();
        System.out.println("提交事务");
    }
}
  • 测试类:TestProxy
package com.allen.proxy;

import com.allen.proxy.impl.UserDao;
import com.allen.proxy.impl.UserDaoProxy;
import org.junit.Test;

/**
 * @author :jhys
 * @date :Created in 2021/7/16 19:23
 * @Description :
 */
public class StaticUserTest {

    @Test
    public void testStaticProxy() {
        // 目标对象
        IUserDao target = new UserDao();

        // 代理对象
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();
    }
}
  • 输出结果

开启事务
保存数据
提交事务

三、动态代理

动态代理利用了JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。

静态代理与动态代理的区别主要在:

  • 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
  • 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

所以,一旦我们明确接口,完全可以通过接口的Class对象,创建一个代理Class,通过代理Class即可创建代理对象。

 

 

preview

preview

特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

JDK中生成代理对象主要涉及的类有

static Object    newProxyInstance(ClassLoader loader,  //指定当前目标对象使用类加载器

 Class<?>[] interfaces,    //目标对象实现的接口的类型
 InvocationHandler h      //事件处理器
) 
//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
 Object    invoke(Object proxy, Method method, Object[] args) 
// 在代理实例上处理方法调用并返回结果。

举例:保存用户功能的动态代理实现

  • 接口类: IUserDao
package com.proxy;

public interface IUserDao {
    public void save();
}
  • 目标对象:UserDao
package com.proxy;

public class UserDao implements IUserDao{

    @Override
    public void save() {
        System.out.println("保存数据");
    }
}
  • 动态代理对象:UserProxyFactory
package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory {

    private Object target;// 维护一个目标对象

    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 为目标对象生成代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开启事务");

                        // 执行目标对象方法
                        Object returnValue = method.invoke(target, args);

                        System.out.println("提交事务");
                        return null;
                    }
                });
    }
}
  • 测试类:TestProxy
package com.proxy;

import org.junit.Test;

public class TestProxy {

    @Test
    public void testDynamicProxy (){
        IUserDao target = new UserDao();
        System.out.println(target.getClass());  //输出目标对象信息
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println(proxy.getClass());  //输出代理对象信息
        proxy.save();  //执行代理方法
    }
}
  • 输出结果
class com.proxy.UserDao
class com.sun.proxy.$Proxy4
开启事务
保存数据
提交事务

小结

我想了个很骚的比喻,希望能解释清楚:

接口Class对象是大内太监,里面的方法和字段比做他的一身武艺,但是他没有小DD(构造器),所以不能new实例。一身武艺后继无人。

那怎么办呢?

正常途径(implements):

写一个类,实现该接口。这个就相当于大街上拉了一个人,认他做干爹。一身武艺传给他,只是比他干爹多了小DD,可以new实例。

非正常途径(动态代理):

通过妙手圣医Proxy的克隆大法(Proxy.getProxyClass()),克隆一个Class,但是有小DD。所以这个克隆人Class可以创建实例,也就是代理对象。

代理Class其实就是附有构造器的接口Class,一样的类结构信息,却能创建实例。

参考资料:https://segmentfault.com/a/1190000011291179 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Vermont_/article/details/118817390

几种常用的设计模式-爱代码爱编程

设计模式(Design Patterns)                                   ——可复用面向对象软件的基础 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、

java开发中的常用的设计模式_不远阑珊处的博客-爱代码爱编程_java开发中常用的设计模式

设计模式(Design Patterns)                                   ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都

面试——常用的设计模式_斯维特哈特的博客-爱代码爱编程

一、软件设计模式的几种分类: 1.1.  创建型 创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构优势。创建型模式主要有简单工厂模式(并不是23种设计模式之一)、工厂方法、抽象工厂模式、单例模式、生成器模式和原型模式。 1.2.  结构型 用于帮助将多个对象组织成更大的结构。结构型模

java开发中的23种设计模式详解_这个云彩好看的博客-爱代码爱编程_java设计模式

                转自:http://zz563143188.iteye.com/blog/1847029     设计模式(Design Patterns)                                   ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分

常用的7种设计模式简单介绍_快乐肥柴的博客-爱代码爱编程

常用的7种设计模式简单介绍 一、面向对象的六大原则 单一职责原则 将一组相关性很高的函数、数据封装到一个类中。换句话说,一个类应该有单一的职责。开闭原则 一个类应该对于扩展是开放的,但是对于修改是封闭的。里氏替换原则 里

java常用的设计模式-爱代码爱编程

设计模式是编程解决实际问题或类似问题的最佳实践,Java编程中处处都是对象,对象需要创建,对象间需要相互调用,对象的模板是类,类与类需要相互关联引用,如何通用解决上述问题,经过长时间的编程实践总结出来的统筹方法就是设计模式,

java常见的五种设计模式-爱代码爱编程

Java常见的五种设计模式 1 工厂模式2 静态工厂模式3 单例模式4 建造者模式5 原型模式 1 工厂模式 常用的为静态工厂模式,类似于工具类,只负责输入输出的功能,静态的好处是不用去实例化这个工厂,可以直

Java常见设计模式-爱代码爱编程

Java常见设计模式 一、工厂设计模式   简单工厂模式:将创建对象的逻辑判断放在了工厂类中(第三方类),客户并不知道具体有哪些类,客户端需要什么商品只需要修改工厂类的调用而不需要修改客户端,降低了客户端与具体商品的依赖,但违背了开闭原则(在新增具体类的时候,必须修改工厂类)   工厂方法模式:设置工厂接口,将实例化产品的操作延迟到工厂接口的子类中实行

常用设计模式-爱代码爱编程

设计模式 从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联和组合关系的充分理解。 正确使用设计模式具有一下优点: 1、可以提高程序员的思维能力、编码能力和设计能力。 2、使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,

java中常见的设计模式_在Java中10种常见设计模式详细介绍-爱代码爱编程

通常,一个设计模式描述了一个被证明可行的方案。这些方案非常广泛,是具有完整定义的最常用的行式。普通模式有4个基本要素:模式名称(pattern name)、问题(problem)、解决方案(solution)、效果(consequences)。 部分常见的Java设计模式有以下10种: 1、抽象工厂模式(Abstract Factory):提供一个

几种常用的设计模式 (Design Pattern)-爱代码爱编程

文章目录 设计模式(Design Pattern)一、设计模式的分类1. 基础型模式 (Fundamental Pattern)2. 创建型模式 (Creational Pattern)3. 结构型模式 (Structural Pattern)4. 行为型模式 (Behavioral Pattern)5. 并发型模式 (Concurrency Pa

常用的几种设计模式详解-爱代码爱编程

设计模式的概述 设计模式分类 创建型模式 特点是将对象的创建与使用分离(解耦),有 单例、原型、工厂方法、抽象工厂、建造者等5种。 结构型模式 用于描述如何将类或对象按某种布局组成更大的结构,代理、适配器、桥接、装饰、享元、组合等7种。 行为型模式 用于描述类或对象之间相互协作共同完成 单个对象无法完成的任务,模板方法、策略命令、职责链、状态观察

Java常见设计模式总结-爱代码爱编程

 一、设计模式总述: 1、什么是设计模式:         设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之

常见的设计模式-爱代码爱编程

文章目录 策略模式观察者模式装饰者模式工厂模式单例模式(单件模式)命令模式适配器模式与外观模式面向对象适配器:类适配器外观模式模板方法模式迭代器与组合模式迭代器组合模式状态模式复合模式 策略模式 策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 设计原则 多用组合,少用继承。

十种常用的设计模式(大部分自己总结,部分摘抄)-爱代码爱编程

设计模式总结 1.       单例模式: 实现方式: a) 将被实现的类的构造方法设计成private的。 b) 添加此类引用的静态成员变量,并为其实例化。 c)  在被实现的类中提供公共的CreateInstance函数,返回实例化的此类,就是b中的静态成员变量。   应用场景: 优点:      1.在单例模式中,活动的单例只有一个实