深入解析设计模式:分类、创建与结构模式详解

一.设计模式 1.简介
设计模式是经过分类编目的代码设计经验。
设计模式的基本要素;设计模式的分类,其一,模式依据其目的可进行划分;其二,范围准则是分类的一个方面。
指定模式主要是用于类还是用于对象。
3.创建模式
创建模式指的是对类的实例化过程进行抽象化。
一些系统在创建对象时,需要去动态地确定创建对象的方式以及创建哪些对象。创建模式对怎样构造和封装这些动态的决定进行了描述。
4.结构模式
结构模式描述如何把类或者对象组合在一起以形成更大的结构,这种结构模式描述了两类不同的事物,一类是类,另一类是类的实例。
5、行为模式
在不同对象之间划分责任与算法,同时解决对象之间的相互作用方式
2.工厂模式 1)定义
工厂模式在 Java 中较为常用。它属于创建型模式。这种模式能提供创建对象的最佳方式。
工厂模式又叫静态工厂方法模式、简单工厂
2)结构
工厂类是模式的核心。此类包含着必要的判断逻辑,能够决定在何种情况下创建某一个产品类的实例。客户端无需直接承担创建产品对象的责任,只需负责“消费”产品。简单工厂模式凭借这种方式实现了对责任的划分。
创建测试接口及实现类,
3)创建工厂
通过中间的工厂调用其他类的方法
3.单例(Singleton)模式 1)定义
单例模式能保证某一个类仅有一个实例存在。它会自行进行实例化操作,并且将这个实例提供给整个系统。
这里有三个要点:
某个类仅能有一个实例,类必须自己去创建这个实例,并且以公共、统一的方式将这个实例提供给整个系统。 应用。
很多时候整个系统只需拥有一个全局对象,这有利于我们对系统整体的行为进行协调。
在某个服务器程序里,该服务器的配置信息被存放在一个文件当中。这些配置数据是由一个单例对象来进行统一读取的。接着,服务进程中的其他对象会通过这个单例对象去获取这些配置信息。
这种方式简化了在复杂环境下的配置管理
借助编程语言自身所具有的语法特性,对某个类进行强制限制,使其不能创建出多个实例。
3)分类 1.饿汉式EngerSingLeton
直接创建对象
public class EagerSingleton {
private static final EagerSingleton m_instance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return m_instance;
}
}
2.懒汉式LazySingLeton
先判断在创建对象
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)结构 … 二.代理模式 1.简介
大家对“代理”这个词并不陌生。我们都知晓代理商。简单来讲,代理商就是替厂家售卖商品。厂家会委托代理来为其销售商品,而顾客则会找代理购买商品。
使用代理通常有两个优点,并且这两个优点能够分别与我们提到的代理商的几个特点相对应。
关于代理商,其一,我们从他们处购买东西时,往往不清楚背后的厂家具体是谁,这意味着委托者对于我们而言是不可见的;其二,代理能够对顾客进行定位,从而更精准地售卖给有需求的客户群体。
代理模式是 Java 设计模式中常用的一种。其特征在于,代理类与委托类具备相同的接口。代理类主要承担以下任务:为委托类预处理消息;对消息进行过滤;把消息转发给委托类;以及在事后对消息进行处理等。
代理类和委托类通常存在关联关系。一个代理类的对象会与一个委托类的对象相关联。代理类的对象自身并不实际去实现服务。它是通过调用委托类的对象的相关方法,从而来提供特定的服务。
代理模式的作用是为其他对象提供一种代理,从而控制对该对象的访问。它创建一个代理对象,让这个代理对象充当客户端与目标对象之间的中介。其主要目的在于保护目标对象或者增强目标对象。
通过使用代理模式,通常有以下两个优点:
隐藏被代理类的实现能够实现客户与被代理类间的解耦,并且在不修改被代理类代码的情况下还能够做一些额外的处理。
按照代理的创建时期,代理类可以分为两种。
3)Proxy模式结构
由三部分组成:
2.静态代理
如果代理类在程序运行之前就已经存在了,那么这种代理方式就叫做静态代理。在这种情况下,代理类通常是我们在 Java 代码中定义出来的。
所谓的静态代理,是通过声明一个明确的代理类去访问源对象。一个代理仅能服务于一种产品。当存在 n 种产品时,就需要 n 个代理。这样的情况不利于业务的发展。
我们拥有两个接口,分别是 Computer 和 Phone,并且每个接口都对应着一个实现类。
定义接口,也就是代理接口;定义实现类,即委托类;定义代理类 Proxy,这个代理类最终还是会调用委托类来实现业务操作。
通过代理类调用的方法调用实现类的方法
1)优缺点
静态代理的代码较为简单且容易理解。这种模式有着自身的优势,然而,它也存在着较为明显的不足之处:
3.动态代理
代理类在程序运行期间创建的代理方式被称作动态代理。即在此情况下,代理类并非在 Java 代码中预先定义好的,而是在运行过程中依据我们在 Java 代码里的指示而动态生成的,在程序运行时,通过运用反射机制来动态创建出代理对象。
JDK从1.3版本就开始支持动态代理类的创建。
java.lang.reflect 类库中提供了三个类,它们直接对代理模式提供支持,分别是 Proxy、InvocationHandler 和 Method
1)JDK原生动态代理
Java 原生对其提供支持,无需外部依赖。不过,它仅能基于接口来进行代理,这意味着需要动态代理的对象必须要实现某个接口。
Proxy类
Proxy 具备创建动态代理类和实例的功能,它拥有用于此的静态方法。同时,它还是由这些静态方法所创建的所有动态代理类的上一级类别。
核心方法 newProxyInstance 能够返回一个具有指定接口的代理类实例,这个实例可以把方法调用指派给指定的调用处理程序。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//参数说明:
定义代理类的类加载器为 loader;代理类要实现的接口列表是 interfaces;指派方法调用的调用处理程序是 h。
类加载器在 Proxy 类的 newProxyInstance()方法中需要一个 ClassLoader 类的实例,而这个 ClassLoader 实际上对应的就是类加载器。
InvocationHandler类
代理实例的调用处理程序 实现的接口
每个代码实例都有一个与之相关联的调用处理程序。当对代理实例调用方法时,会对该方法调用进行编码,并将其指派给其调用处理程序的 invoke 方法。
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 替换掉。
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;
}
Method类
Method 会提供关于类或接口上某个单独方法的信息,同时也会告知如何访问该方法。所反映出的方法可以是类方法,也可以是实例方法,其中还包括抽象方法。
主要方法是 invoke:调用带有指定参数的指定对象所对应的由该 Method 对象所表示的基础方法。
public Object invoke(Object obj,
Object... args)
参数包括 obj,这是从中调用基础方法的对象;还有 args,是用于方法调用的参数。
2)CGLIB动态代理
[CGLIB] CGLIB
CGLIB 以继承的方式来实现代理,使得需要代理的类成为 Enhancer 的父类。它不依赖于目标对象是否实现了接口,都能够进行代理。然而,它无法处理 Final 的情况,这需要依赖外包来解决。
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代理的区别
通过调用方法 method,将参数 objects 传递给目标对象 target,从而得到对象结果 object result。
System 显示了“售后处理之后被调用”;
return result;
}
});
//创建代理对象
return enhancer.create();
}
## 4.JDK代理与CGLIB代理的区别
- JDK动态代理实现接口,CGLIB动态继承思想
JDK 动态代理在目标对象存在接口的情况下,其执行效率比 CIGLIB 要高。
如果对象具备接口实现,那么就选择 JDK 代理;倘若对象没有接口实现,就选择 CGILB 代。