7.javaSE基础进阶_设计模式和代理模式(静态代理JDK和动态代理CGLIB)

文章目录

一.设计模式

1.简介

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

  • 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
  • 每个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。
  • 设计模式的贯穿思想:针对接口编程,最大限度的适应变化,实现代码重用

1)设计模式基本要素

  • 模式名称(pattern name):一个助记名, 它用一两个词来描述模式的问题、解决方案和效果。
  • **问题(problem):**描述了应该在何时使用模式它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。
  • **解决方案(solution):**描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。
  • 效果(consequences) : 描述了模式应用的效果及使用模式应权衡的问题。

2)设计模式的分类

1.模式依据其目的可分为:
  • 创建型(Creational) 创建型模式与对象的创建有关
  • 结构型 (Structural) 结构型模式处理类或对象的组合
  • 行为型(Behavioral) 行为型模式对类或对象怎样交互和怎样分配职责进行描述
2.第二是范围准则

指定模式主要是用于类还是用于对象。

  • 类模式:处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了。
  • 对象模式:处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性。
3.创建模式

创建模式(Creational Pattern):是对类的实例化过程的抽象化

一些系统在创建对象时,需要动态地决定怎样创建对象、创建哪些对象,创建模式描述了怎样构造和封装这些动态的决定:

  • 工厂方法(Factory Method)
  • 抽象工厂(Abstract Factory)
  • 单例(Singletion)
  • 原型(Prototype)
  • 建造者(Builder)
4.结构模式

结构模式(Structural Pattern):描述如何将类或者对象结合在一起形成更大的结构,结构模式描述了两种不同的东西:类、类的实例

  • 适配器(Adapter)
  • 桥接(Bridge)
  • 组合(Composite)
  • 装饰(Decorator)
  • 外观(Facade)
  • 享元(Flyweight)
  • 代理(Proxy)
5、行为模式

在不同的对象之间划分责任和算法,而且解决对象之间如何相互作用

  • 迭代(Iterator)
  • 模板方法(Template Method)
  • 职责链(Chain of Responsibility)
  • 访问者(Visitor)
  • 中介者(Mediator)
  • 观察者(Observer)
  • 备忘录(Memento)
  • 状态(State)
  • 策略(Strategy)
  • 命令(Command)
  • 解释器(Interpreter)

2.工厂模式

1)定义

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

工厂模式又叫静态工厂方法模式、简单工厂

2)结构

模式的核心是工厂类。这个类含有必要的判断逻辑,可以决定在什么时候创建那一个产品类的实例。而客户端则可以免除直接创建产品对象的责任,而仅仅负责"消费"产品。简单工厂模式通过这种做法实现了对责任的分割

  • 工厂类(Creator)角色:担任这个角色的是工厂模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体Java类实现。
  • 抽象产品(Product)角色:担任这个角色的类是由工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个Java接口或者java抽象类实现。
  • 具体产品(Concrete Product)角色:工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色有一个具体java类实现

创建测试接口及实现类,

3)创建工厂

通过中间的工厂调用其他类的方法

3.单例(Singleton)模式

1)定义

单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

这里有三个要点:

  1. 某个类只能有一个实例
  2. 类必须自行创建这个实例
  3. 以公共、统一的方式向整个系统提供这个实例

2)应用

许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。

比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。

这种方式简化了在复杂环境下的配置管理

借助编程语言自身的语法特性,强制限制某个类,不能创建多个实例

3)分类

1.饿汉式EngerSingLeton

++直接创建对象++

java 复制代码
public class EagerSingleton {
    private static final EagerSingleton m_instance = new EagerSingleton();
​
    private EagerSingleton() {
    }
​
    public static EagerSingleton getInstance() {
        return m_instance;
    }
}
2.懒汉式LazySingLeton

++先判断在创建对象++

java 复制代码
public class LazySingleton {
    private static LazySingleton m_instance = null;
​
    private LazySingleton() {
    }
​
    public static LazySingleton getInstance() {
        if (m_instance == null) {
            m_instance = new LazySingleton();
        }
        return m_instance;
    }
}

4.++Prototype模式++

Prototype模式即原型模式,原型模式其实是一个比较单纯的设计模式,其目的就是利用一个原型对象,快速地生成一批对象,从而避免重复的新建过程。

工作原理是:通过将一个原型对象传给一个要新建的对象,新建对象通过请求原型对象拷贝它们,然后自己来实施创建

1)适应场景

主要适用于以下情况:

  • 构建函数相对比较复杂
  • 构建函数不能被不相关的人调用
  • 一批对象中绝大部分对象的属性一致,而只有极少数不同

2)结构

  • Prototype:声明一个克隆自身的接口或抽象类
  • ConcretePrototype:实现一个克隆自身的操作
  • Client:让一个原型来克隆自身从而创建一个新的对象

...

二.代理模式

1.简介

代理这个词相信大家并不陌生,我们大家都知道代理商,简单地说就是代替厂家卖商品,厂家委托代理为其销售商品,顾客找代理购买商品。

通过使用代理,通常有两个优点,并且能够分别与我们提到的代理商的几个特点对应起来:

  1. 关于代理商,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,委托者对我们来说是不可见的;
  2. 代理可以对顾客进行定位,更精确的售卖给需要的客户群体

1)定义:

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

代理模式:为其他对象提供一种代理以控制对这个对象的访问,也就是创建一个代理对象作为客户端和目标对象之间的中介,主要目的就是保护目标对象或增强目标对象

通过使用代理模式,通常有以下两个优点:

  1. 可以隐藏被代理类的实现
  2. 可以实现客户与被代理类间的解耦,在不修改被代理类代码的情况下能够做一些额外的处理

2)++分类++

按照代理的创建时期,代理类可以分为两种。

  • ++静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了**++
  • ++动态代理:在程序运行时,运用反射机制动态创建而成++

3)Proxy模式结构

由三部分组成:

  • Proxy:保存一个引用使得代理可以访问实体。控制对实体的存取,并可能负责创建和删除它,其他功能依赖于代理的类型。
  • Subject:定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
  • RealSubject:定义Proxy所代表的实体。

2.静态代理

若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的

所谓的静态代理,就是通过声明一个明确的代理类来访问源对象,一个代理只能服务于一种产品,当有n种产品时,就需要n个代理,这样就不利于业务的发展。

举例:我们有两个接口,Computer和 Phone,每个接口都有一个实现类

  1. 定义接口(代理接口)
  2. 定义实现类(委托类)
  3. 定义代理类Proxy(代理类,最终还是调用委托类实现业务操作)

通过代理类调用的方法调用实现类的方法

1)优缺点

静态代理的代码非常简单易懂,这种模式虽好,但是也有明显的缺点:

  • 会存在大量冗余的代理类,这里只有两个接口,如果有n个接口,那么就要定义n个代理类。
  • 不易维护,一旦接口更改,代理类和被代理类都要更改。

3.动态代理

代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的指示动态生成的 ,在程序运行时,运用反射机制动态创建而成代理对象。

JDK从1.3版本就开始支持动态代理类的创建。

java.lang.reflect类库中提供三个类直接支持代理模式:ProxyInvocationHandlerMethod

1)JDK原生动态代理

是Java原生支持的,不需要外部依赖,但是它只能基于接口进行代理(需要动态代理的对象必须实现与某个接口)

  1. Proxy类

    Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

    核心方法newProxyInstance:返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

java 复制代码
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
 //参数说明:
//loader - 定义代理类的类加载器 interfaces - 代理类要实现的接口列表 h - 指派方法调用的调用处理程序
//Ps:类加载器 在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器
  1. InvocationHandler类

    代理实例的调用处理程序 实现的接口

    每个代码实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法

java 复制代码
package java.lang.reflect;
public interface InvocationHandler { 
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
//参数说明:
//Object proxy:在其上调用方法的代理实例。
//Method method:要调用的方法
//Object\[] args:方法调用时所需要的参数
//可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
java 复制代码
public class JDKProxy implements InvocationHandler {
    private final Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        Object obj = method.invoke(target, args);
        long end = System.currentTimeMillis();
        System.out.println(method.getName() + "耗时" + (end - start) + "ms");
        return obj;
    }
  1. Method类

    Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

    主要方法invoke:对带有指定参数的指定对象调用由此 Method 对象表示的基础方法

java 复制代码
public Object invoke(Object obj,
                     Object... args)
//  参数: obj - 从中调用基础方法的对象 args - 用于方法调用的参数

2)CGLIB动态代理

[CGLIB] https://mvnrepository.com/artifact/cglib/cglib CGLIB

CGLIB通过继承的方式进行代理,(让需要代理的类成为Enhancer的父类),无论目标对象有没有实现接口都可以代理,但是无法处理Final的情况(依赖外包)

  • 引入依赖

    导入cglib-3.1.jarasm-4.2.jar

  • 使用流程

    1. 创建代理对象

    2. 得到委托类

    3. 得到代理类

    4. 通过代理对象调用方法

java 复制代码
public class CGLibProxy {
    public static Object getProxy(final Object target) {
        //创建enhancer对象
        Enhancer enhancer = new Enhancer();
        //创建代理对象为超级类
        enhancer.setSuperclass(target.getClass());
        //调用应用
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * @author Arran
             * @description  
             * @params [o, method, objects, methodProxy] 
             * @return java.lang.Object 
             * @date  2024/06/27 下午 03:13
             */
            
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("售前咨询 之前被调用");
                Object result = method.invoke(target, objects);
                System.out.println("售后处理 之后被调用");
                return result;
            }
        });
        //创建代理对象
        return enhancer.create();
    }
}

4.JDK代理与CGLIB代理的区别

  • JDK动态代理实现接口,CGLIB动态继承思想

  • JDK动态代理(目标对象存在接口时)执行效率高于CIGLIB

  • 如果对象有接口实现,选择JDK代理,如果没有接口实现选择CGILB代

 Object result = method.invoke(target, objects);
            System.out.println("售后处理 之后被调用");
            return result;
        }
    });
    //创建代理对象
    return enhancer.create();
}

}

## 4.JDK代理与CGLIB代理的区别

- JDK动态代理实现接口,CGLIB动态继承思想

- JDK动态代理(目标对象存在接口时)执行效率高于CIGLIB

- 如果对象有接口实现,选择JDK代理,如果没有接口实现选择CGILB代

​     
相关推荐
极客先躯几秒前
中级java每日一道面试题-2024年7月3日
java·开发语言·java每日一道面试题
AskHarries17 分钟前
Spring Boot集成geode快速入门Demo
java·spring boot·后端·geode
小哇66630 分钟前
SpringBoot整合Minio
java·spring boot·spring
Tech Synapse43 分钟前
Java循环创建对象内存溢出怎么解决
java·开发语言·jvm
IT·陈寒43 分钟前
Kotlin vs Java:深入解析两者之间的最新差异与优劣(全面指南)
java·python·kotlin
行动π技术博客1 小时前
spring中IOC相关介绍
java·spring·rpc
吃青椒的小新1 小时前
独一无二的设计模式——单例模式(Java实现)
java·后端·单例模式·设计模式
天才梦浪1 小时前
开源租房项目
java·项目
杰哥在此1 小时前
Java面试题:解释跨站脚本攻击(XSS)的原理,并讨论如何防范
java·开发语言·面试·编程·xss
Czi橙2 小时前
玩玩快速冥(LeetCode50题与70题以及联系斐波那契)
java·算法·快速幂·斐波那契