java设计模式

GOF(Group For Four)23设计模式

1. 创建型模式

1.1. 单例模式

只生成一个实例

1.1.1. 饿汉式

线程安全,调用效率高。不能延时加载

1
2
3
4
5
6
7
8
9
10
11
public class Singleton{
//类初始化时,立即加载这个对象加载时,天然是线程安全的
private static Singleton instance = new Singleton();

private Singleton(){}

//方法没有同步,调用效率高
public static Singleton getInstance(){
return instance;
}
}

1.1.2. 懒汉式

线程安全,调用效率不高,可以延时加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton{

private static Singleton instance = null;

private Singleton(){}

public static synchronized Singleton getInstance(){

if(instance == null){
instance = new Singleton();
}
return instance;
}
}

1.1.3. 双重检测锁式

由于JVM底层内部模型原因,偶尔会出问题,不建议使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Singleton{

private static Singleton instance = null;

private Singleton(){}

public static Singleton getInstance(){

if(instance == null){
Singleton s;
synchronized(Singleton.class){
s = instance;
if(s==null){
synchronized(Singleton.class){
if(s==null){
s = new Singleton();
}
}
instance = s;
}
}
}
return instance;
}
}

1.1.4. 静态内部类式

线程安全,调用效率高,不能延时加载

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton{

private static class Singletonclass{
private static final Singleton instance = new Singleton();
}

private Singleton(){}

public static Singleton getInstance(){

return Singletonclass.instance;
}
}

1.1.5. 枚举单例

线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化漏洞

1
2
3
4
5
6
7
8
public enum Singleton{

INSTANCE;

public void singletonOperation(){

}
}

1.2. 工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Car{
public void run();
}

public class Audi implements Car{
public void run(){
System.out.println("奥迪在跑");
}
}

public class Baoma implements Car{
public void run(){
System.out.println("宝马在跑");
}
}

实现创建者和调用者分离

1.2.1. 简单工厂模式-静态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CarFactory{
public static Car createCar(String type){
Car c = null;
if("奥迪".equals(type)){
c = new Audi();
}else if("宝马".equals(type)){
c = new Baoma();
}
return c;
}
}

//2
public interface CarFactory{
Car createCar();
}

public class AudiFactory implements CarFactory{
public Car createCar(){
return new Audi();
}
}

Car audi = new AudiFactory().creatCar();

1.3. 抽象工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public interface Engine{
void run();
}

public class LuxuryEngine implements Engine{
@Override
public void run(){

}
}
public class LowEngine implements Engine{
@Override
public void run(){

}
}

public interface Seat{
void message();
}

public class LuxurySeat implements Seat{
@Override
public void message(){

}
}

public class LowSeat implements Seat{
@Override
public void message(){

}
}

public interface CarFatory{
Engine createEngine();
Seat createSeat();
}

public class LuxuryCarFactory implements CarFactory{
@Override
public Engine createEngine(){

}
@Override
public Seat createSeat(){

}
}

1.4. 建造者模式

1.4.1. Airship

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package builder;

public class Airship {

private String engine;
private String escapeTower;
private String orbitalModule;
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public String getEscapeTower() {
return escapeTower;
}
public void setEscapeTower(String escapeTower) {
this.escapeTower = escapeTower;
}
public String getOrbitalModule() {
return orbitalModule;
}
public void setOrbitalModule(String orbitalModule) {
this.orbitalModule = orbitalModule;
}
@Override
public String toString() {
return "Airship [engine=" + engine + ", escapeTower=" + escapeTower + ", orbitalModule=" + orbitalModule + "]";
}
}

1.4.2. AirshipBuilder

1
2
3
4
5
6
7
8
9
10
package builder;

public interface AirshipBuilder {

String builderEngine();
String builderOrbitalModule();
String builderEscapeTower();

}

1.4.3. AirshipDirector

1
2
3
4
5
6
7
8
package builder;

public interface AirshipDirector {

Airship createAirship(AirshipBuilder builder);

}

1.4.4. CeacreteAirshipBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package builder;

public class CeacreteAirshipBuilder implements AirshipBuilder {

@Override
public String builderEngine() {
return "发动机";
}

@Override
public String builderOrbitalModule() {
return "轨道仓";
}

@Override
public String builderEscapeTower() {
return "逃逸塔";
}
}

1.4.5. CeacreteAirshipDirector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package builder;

public class CeacreteAirshipDirector implements AirshipDirector {

@Override
public Airship createAirship(AirshipBuilder builder) {

Airship airship = new Airship();
airship.setEngine(builder.builderEngine());
airship.setEscapeTower(builder.builderEscapeTower());
airship.setOrbitalModule(builder.builderOrbitalModule());

return airship;
}
}

1.4.6. Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package builder;

public class Client {

public static void main(String[] args) {

AirshipDirector director = new CeacreteAirshipDirector();

Airship airship=director.createAirship(new CeacreteAirshipBuilder());

System.out.println(airship);
}
}

1.5. 原型模式

2. 结构型模式

2.1. 适配器模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Adaptee{
public void method(){

}
}

public interface Target{
void handle();
}

//1
public class Adapter extends Adaptee implements Target{
public void handle(){

}
}

//2
public class Adapter implements Target{

private Adaptee adaptee;

public void handle(){

}
}

2.2. 桥接模式

多层继承结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//电脑品牌
public interface Brand{
void sale();
}
public class Lenvo implements Brand{
@Override
public void sale(){

}
}
public class Dell implements Brand{
@Override
public void sale(){

}
}

//电脑
public class computer{
protected Brand brand;
public Computer(Brand brand){
this.brand=brand;
}

public void sale(){
brand.sale();
}
}

public class Laptop extends Computer{
public Laptop(Brand brand){
super(brand);
}
}

Computer c = new Laptop(new Dell());

2.3. 装饰模式

IO流 BufferInputerStream(new InputStream())

线程 new Thread(new Runnable())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public interface Car{
void move();
}

//真实对象
public class Baoma implements Car{
public void move(){

}
}
//装饰对象
public class SuperCar implements Car{

protected Car car;
public SuperCar(Car car){
this.car = car;
}

public void move(){
car.move();
}
}

//具体装饰对象
public class FlyCar extends SuperCar{
public FlyCar(Car car){
super(car);
}

public void fly(){
System.out.println("...");
}
public void move(){
super.move();
fly(); //添加装饰
}
}

Car car = new Baoma();
car.move();
FlyCar fly = new FlyCar(car);
fly.move(); //添加了功能

2.4. 组合模式

树形结构

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Component{
void operation();
}

public interface Leaf extends Component{

}

public interface extends Component{
void add(Component c);
void remove(Component c);
Component getChlid();
}

2.5. 外观模式

简单封装

2.6. 享元模式

1

2.7. 代理模式

使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

2.7.1. 静态代理模式

静态代理中,我们对目标对象的每个方法的增强都是手动完成的

它的适用性不高:

  • 不灵活:接口一旦新增加方法,目标对象和代理对象都要进行修改

  • 麻烦:需要对每个目标类都单独写一个代理类

从 JVM 层面来说,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件

静态代理实现步骤

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//定义同一个接口
public interface Star{
void sing();
}

//ProxyStar - 代理类
public class ProxyStar implements Star{
private Star star;

public proxy(Star star){
this.star=star;
}
@Override
public void sing(){
star.sing();
}
}

//RealStar - 实际类
public class RealStar implements Star{
@Override
public void sing(){

}
}

//Client
public class client{
public static void main(String[] args){
Star star=new RealStar();
ProxyStar proxy = new ProxyStar(star);

proxy.sing();
}
}

2.7.2. 动态代理模式

相比于静态代理来说,动态代理更加灵活。不需要针对每个目标类都单独创建一个代理类,并且也不需要我们必须实现接口,我们可以直接代理实现类( CGLIB 动态代理机制)。

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的

Spring AOP、RPC 框架的实现都依赖了动态代理

就 Java 来说,动态代理的实现方式有很多种,比如 JDK 动态代理CGLIB 动态代理等等

2.7.2.1. Java动态代理机制

实现InvocationHandler接口,利用Proxy类的newProxyInstance方法生成一个代理对象

1
2
3
4
5
6
7
8
9
/**
* @param loader - 类加载器,用于加载代理对象
* @param interfaces - 被代理类实现的一些接口
* @param h- 实现了InvocationHandler接口的对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{}

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

1
2
3
4
5
6
7
8
9
10
11
public interface InvocationHandler {

/**
* 使用代理对象调用方法的时候实际会调用到这个方法
* @param proxy - 动态生成的代理类
* @param method - 与代理类对象调用的方法相对应
* @param args - 当前 method 方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

也就是说:通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。 在 invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情。

当动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

JDK 动态代理类使用步骤

  1. 定义一个接口及其实现类;
  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package Proxy;

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

//定义一个接口
public interface Star{
public void sing(String name);
}

//RealStar - 实际类
public class RealStar implements Star{
@Override
public void sing(String name) {
System.out.println(name);
}
}

//ProxyInvocation - 代理类
public class ProxyInvocation implements InvocationHandler{

//真实的对象
Star star;

public ProxyInvocation(Star star){
this.star = star;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用方法之前,添加自己的操作
System.out.println("Before method "+method.getName());
Object obj = method.invoke(star, args);
//调用方法之后,添加自己的操作
System.out.println("After method "+method.getName());

return obj;
}


//Client
package Proxy;

import java.lang.reflect.Proxy;

public class Client {

public static void main(String[] args) {

Star star = new RealStar();

Star proxy = (Star)Proxy.newProxyInstance(
star.getClass().getClassLoader(),
star.getClass().getInterfaces(),
new ProxyInvocation(star));

proxy.sing("ABC");
/*
Before method sing
ABC
After method sing
*/
}
}

或者使用代理对象的工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
// 目标类的类加载
target.getClass().getClassLoader(),
// 代理需要实现的接口,可指定多个
target.getClass().getInterfaces(),
// 代理对象对应的自定义 InvocationHandler
new DebugInvocationHandler(target)
);
}
}

//使用
Star proxy = (Star)JdkProxyFactory.getProxy(new Star());
proxy.sing("ABC");

2.7.2.2. CGLIB 动态代理机制

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理

在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心

自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法

通过Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

1
2
3
4
5
6
7
8
9
10
11
12
public interface MethodInterceptor extends Callback{
/**
*拦截被代理类中的方法
* @param o 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param objects 方法入参
* @param methodProxy 用于调用原始方法
* @return
* @throws Throwable
*/
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

CGLIB动态代理类使用步骤

  1. 定义一个类
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似
  3. 通过 Enhancer 类的 create()创建代理类

代码示例

1
2
3
4
5
6
<!--    添加依赖    -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
实际类
*/
class RealStar{
public void sing(String name) {
System.out.println(name);
}
}

/*
自定义MethodInterceptor
*/
class myMethodInterceptor implements MethodInterceptor{

/**
*
* @param o 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param objects 方法入参
* @param methodProxy 用于调用原始方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

System.out.println("Before method "+method.getName());

Object obj = methodProxy.invokeSuper(o,objects);

System.out.println("After method "+method.getName());

return obj;
}
}

/*
代理类
*/
class CglibProxyFactory{

public static Object getProxy(Class<?> clazz) {

//创建动态代理增强类
Enhancer enhancer = new Enhancer();
//设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
//设置被代理类
enhancer.setSuperclass(clazz);
//设置方法拦截器
enhancer.setCallback(new myMethodInterceptor());
//创建代理类
return enhancer.create();
}
}

/*
使用
*/
@Test
void contextLoads() {
RealStar star = (RealStar) CglibProxyFactory.getProxy(RealStar.class);
star.sing("ABC");
/*
Before method sing
ABC
After method sing
*/
}

2.7.2.3. java动态代理 vs CGLIB 动态代理

  1. JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
  2. 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。

2.7.3. 静态代理 vs 动态代理

  1. 灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的
  2. JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的

3. 行为型模式

3.1. 模版方法模式

3.2. 命令模式

3.3. 迭代器模式

3.4. 观察者模式

3.5. 中介者模式

3.6. 备忘录模式

3.7. 解释器模式

3.8. 状态模式

3.9. 策略模式

3.10. 职责链模式

3.10.1. Leave

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package Chain;

public class Leave {

private String empName;
private String reason;
private int day;

public Leave(String empName, String reason,int day) {
super();
this.empName = empName;
this.reason = reason;
this.day=day;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}

3.10.2. Leader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Chain;

public abstract class Leader {

protected String name;
protected Leader nextLeader;
public Leader(String name) {
super();
this.name = name;
}
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}

public abstract void handleRequest(Leave leave);

}

3.10.3. Manager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Chain;

public class Manager extends Leader {

public Manager(String name) {
super(name);
}

@Override
public void handleRequest(Leave leave) {

if (leave.getDay()<3) {
System.out.println(super.name+ "批准请假");
}else {
if (this.nextLeader!=null) {
this.nextLeader.handleRequest(leave);
}
}

}

}

3.10.4. Director

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package Chain;

public class Director extends Leader {

public Director(String name) {
super(name);
}

@Override
public void handleRequest(Leave leave) {

if (leave.getDay()<10) {
System.out.println(name+"批准");
}else {
this.nextLeader.handleRequest(leave);
}

}

}

3.10.5. Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package Chain;

public class Client {

public static void main(String[] args) {

Leader director = new Director("主管");

Leader manager = new Manager("经理");

manager.setNextLeader(director);

Leave leave = new Leave("员工", "过年", 2);

manager.handleRequest(leave);

Leave leave2 = new Leave("员工", "过年", 5);

manager.handleRequest(leave2);

}

}

3.11. 访问者模式

本文结束  感谢您的阅读
  • 本文作者: Wang Ting
  • 本文链接: /zh-CN/2020/02/07/java设计模式/
  • 发布时间: 2020-02-07 18:56
  • 更新时间: 2022-10-24 20:16
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!