Java23种设计模式

Java23种设计模式

小颜同学 Lv4

Java设计模式:23种设计模式

设计模式的目标:

提升代码重用性、可读性、可扩展性、可靠性,还能降低系统中类与类之间的耦合度,使程序呈现高内聚低耦合的特性。

设计模式的价值:

代码重用性、可读性、可扩展性、可靠性

设计模式常用6大原则:

  1. 单一职责原则(SRP):一个类只应该有一个引起它变化的原因。
  2. 开放封闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
  3. 里氏替换原则(LSP):子类型必须能够替换掉它们的父类型。
  4. 依赖倒置原则(DIP):高层模块不应该依赖于低层模块,两者都应该依赖于抽象接口;抽象接口不应该依赖于具体实现,具体实现应该依赖于抽象接口。
  5. 接口隔离原则(ISP):不应该强迫一个类实现它不需要的接口,应该将接口拆分成更小和更具体的部分,以便客户端只需要知道它们感兴趣的部分。
  6. 迪米特法则(LOD):一个对象应该对其他对象有尽可能少的了解,通常称为“最少知识原则”。

设计模式的种类:

1、创建型模式
用来描述“如何创建对象”,它的主要特点是“将对象的创建和使用分离”
2、结构型模式
用来描述如何将类或对象按照某种布局组成更大的结构
3、行为型模式
用来识别对象之间的常用交流模式以及如何分配职责

一、5种创建型模式

单例模式、建造者模式、抽象工厂模式、原型模式、工厂模式。

1.单例模式

定义
创建某个类的实例,该类的实例在系统中只有这一份
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
应用场景
一个国家只有一个总统:
项目中用于读取配置文件的类;
数据库连接池,因为数据库连接池是一种数据库资源:Spring中,每个Bean默认都是单例的,这样便于Spring容器进行管理:Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行

特点:

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

1)饿汉式

这种方式比较常用,但容易产生垃圾对象
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

1
2
3
4
5
6
7
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}

2)懒汉式,双检锁

在懒汉式基础上加入双重检验锁,保证线程安全和性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

3)静态内部类

使用静态内部类来实现懒汉式单例模式,保证线程安全和性能。这种方式能达到双检锁方式一样的功效,但实现更简单。

1
2
3
4
5
6
7
8
9
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

4)枚举

使用枚举来实现单例模式,保证线程安全和防止反射攻击。
1)将已经有的class转换成枚举单例
PersonEnum.INSTANCE.getInstance()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Data
public class Person {
private String name;
private int age;
}

public enum PersonEnum {
INSTANCE;

private Person instance;
private PersonEnum(){
instance = new Person();
}

public Person getInstance() {
return instance;
}
}

2)直接新建枚举类
PersonSingleton.INSTANCE

1
2
3
4
5
6
7
8
public enum PersonSingleton {
INSTANCE;

private String name;
public String getName() {
return name;
}
}

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
37
38
abstract class Animal {
public abstract void sound();
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
}
// 创建一个工厂类
class AnimalFactory {
// 定义一个静态方法,根据传入的参数创建具体的产品类对象
public static Animal createAnimal(String type) {
if (type.equalsIgnoreCase("dog")) {
return new Dog();
} else if (type.equalsIgnoreCase("cat")) {
return new Cat();
} else {
throw new IllegalArgumentException("Invalid animal type: " + type);
}
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 使用工厂类创建不同的 Animal 对象
Animal dog = AnimalFactory.createAnimal("dog");
dog.sound();
Animal cat = AnimalFactory.createAnimal("cat");
cat.sound();
}
}

3.抽象工厂模式

定义
抽象工厂模式(Abstract Factory Pattern) 是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象
应用场景
系统中有多于一个的产品族,而每次只使用其中某一产品族在很多软件系统中需要更换界面主题或者一键换肤DAO层支持多种类型的数据库,动态切换时。不同操作系统代码差异化,可以切换不同操作系统

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
// 创建一个抽象产品类
abstract class Animal {
public abstract void sound();
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
}
// 创建具体产品类,继承自 Animal 类
class Dog extends Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
}

abstract class AnimalFactory {
// 定义一个抽象方法,用于创建 Animal 对象
public abstract Animal createAnimal();
}
class CatFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
// 创建具体工厂类,实现创建 Animal 对象的接口
class DogFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 创建一个 Dog 对象
AnimalFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.sound();

// 创建一个 Cat 对象
AnimalFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.sound();
}
}

4.原型模式

定义
将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
应用场景
类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。

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
70
71
72
public abstract class Shape implements Cloneable {
private String id;
protected String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void draw();
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Circle extends Shape {
public Circle() {
type = "Circle";
}
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
public class Square extends Shape {
public Square() {
type = "Square";
}
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class ShapeCache {
private static Map<String, Shape> shapeMap = new HashMap<>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
// For each shape run database query and create shape
// shapeMap.put(shapeKey, shape);
// for example, we are adding three shapes
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(), circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(), square);
}
}
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
Shape clonedShape2 = ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
}
}

在上面的代码中,Shape是一个抽象类,它实现了Cloneable接口并重写了clone()方法。Circle和Square是Shape的具体子类,它们实现了draw()方法。ShapeCache类是一个缓存,它存储了Shape对象的副本。PrototypePatternDemo类是一个演示类,它使用ShapeCache来获取Shape对象的副本。

在loadCache()方法中,我们创建了两个Shape对象的副本,并将它们存储在shapeMap中。在main()方法中,我们使用getShape()方法来获取Shape对象的副本,并输出它们的类型。由于我们使用了原型模式,所以我们可以通过复制现有对象来创建新对象,而无需实例化类。

5.建造者模式

定义
将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成不同复杂对象
应用场景
建造者模式一般用在构建流程或者组成部件固定的场合,将这些部件分开构建成为组件对象
再将这些组件对象整合成为目标对象。比如创建一个旅游产品,旅游产品里面有机票,酒店,门票,保险等等,行程定制师可以根据你的要求,组装成一个你满意的产品。
生活中的应用场景,比如汽车中的方向盘,发动机,车架,轮胎等等部件也是多种多样的

在这个示例中,我们创建了Car类作为我们想要构建的复杂对象。然后,我们创建了CarBuilder类,该类逐步构建Car对象,并最终返回它。最后,我们使用CarBuilder来构建Car对象。

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
public class Car {
private String make;
private String model;
private int year;
private String engine;
private int seats;
public Car(String make, String model, int year, String engine, int seats) {
this.make = make;
this.model = model;
this.year = year;
this.engine = engine;
this.seats = seats;
}
// ... getter setter ... //
}
public class CarBuilder {
private String make;
private String model;
private int year;
private String engine;
private int seats;

public CarBuilder setMake(String make) {
this.make = make;
return this;
}

public CarBuilder setModel(String model) {
this.model = model;
return this;
}

public CarBuilder setYear(int year) {
this.year = year;
return this;
}

public CarBuilder setEngine(String engine) {
this.engine = engine;
return this;
}

public CarBuilder setSeats(int seats) {
this.seats = seats;
return this;
}

public Car build() {
return new Car(make, model, year, engine, seats);
}
}

二、7种结构性模式

适配器模式、代理模式、享元模式、外观模式、组合模式、装饰模式、桥接模式

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
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
public class Car {
private String make;
private String model;
private int year;
private String engine;
private int seats;
public Car(String make, String model, int year, String engine, int seats) {
this.make = make;
this.model = model;
this.year = year;
this.engine = engine;
this.seats = seats;
}
// ... getter setter ... //
}
public class CarBuilder {
private String make;
private String model;
private int year;
private String engine;
private int seats;

public CarBuilder setMake(String make) {
this.make = make;
return this;
}

public CarBuilder setModel(String model) {
this.model = model;
return this;
}

public CarBuilder setYear(int year) {
this.year = year;
return this;
}

public CarBuilder setEngine(String engine) {
this.engine = engine;
return this;
}

public CarBuilder setSeats(int seats) {
this.seats = seats;
return this;
}

public Car build() {
return new Car(make, model, year, engine, seats);
}
}

2.桥接模式

定义
把 抽象(Abstraction) 与行为实现(lmplementation) 分离开,保持各部分的独立性以及功能扩展。
应用场景
JDBC连接数据库时,利用驱动来桥接

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
// 首先,我们定义一个 Color 接口,它表示颜色:
public interface Color {
void applyColor();
}
// 然后,我们定义一个 Shape 抽象类,它包含了一个 Color 对象:
public abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
public abstract void applyColor();
}
// 接下来,我们定义两个实现了 Color 接口的具体类:
public class Red implements Color {
@Override
public void applyColor() {
System.out.println("Applying red color");
}
}

public class Blue implements Color {
@Override
public void applyColor() {
System.out.println("Applying blue color");
}
}
// 最后,我们定义两个实现了 Shape 抽象类的具体类:
public class Circle extends Shape {
public Circle(Color color) {
super(color);
}
@Override
public void applyColor() {
System.out.print("Circle applying color: ");
color.applyColor();
}
}

public class Square extends Shape {
public Square(Color color) {
super(color);
}
@Override
public void applyColor() {
System.out.print("Square applying color: ");
color.applyColor();
}
}
// 现在,我们可以使用这些类来创建出对应的对象并调用它们的方法:
public class Test {
public static void main(String[] args) {
Color blue = new Blue();
Shape square = new Square(new Red());
Shape circle = new Circle(blue);
square.applyColor();
circle.applyColor();
}
}

输出结果如下:

1
2
Square applying color: Applying red color
Circle applying color: Applying blue color

这是一个简单的桥接模式实现,它允许我们在运行时动态地改变 Shape 类的颜色而不用影响到 Shape 子类,同时也允许我们增加新的颜色和形状类而无需改变其它现有的类。

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
51
52
53
54
55
56
57
58
59
60
public interface Pizza {
public String getDescription();
public double getCost();
}
// 具体组件
public class PlainPizza implements Pizza {
public String getDescription() {
return "薄饼";
}
public double getCost() {
return 4.00;
}
}
// 装饰器
public abstract class ToppingDecorator implements Pizza {
protected Pizza pizza;
public ToppingDecorator(Pizza pizza) {
this.pizza = pizza;
}
public String getDescription() {
return pizza.getDescription();
}
public double getCost() {
return pizza.getCost();
}
}
// 具体装饰器
public class Cheese extends ToppingDecorator {
public Cheese(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",马苏里拉奶酪";
}
public double getCost() {
return pizza.getCost() + 0.50;
}
}
// 具体装饰器
public class Pepperoni extends ToppingDecorator {
public Pepperoni(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ",意大利辣香肠";
}
public double getCost() {
return pizza.getCost() + 1.00;
}
}
// 客户端代码
public class PizzaShop {
public static void main(String[] args) {
Pizza pizza = new PlainPizza();
pizza = new Cheese(pizza);
pizza = new Pepperoni(pizza);
System.out.println(pizza.getDescription());
System.out.println("成本:$" + pizza.getCost());
}
}

4.组合模式

定义
依据树形结构来组合对象,用来表示部分以及整体层次,比如: 学校、院、系的关系
应用场景
组合模式非常适合有递归迭代性质的结构或者逻辑。即结构上存在树型或者包含关系,逻辑上”整体”和”部分”的行为和状态的对外表现是一致的,或者是类似的。比如目录和文件,目录可以只包含子目录,也可以只包含文件,当然可以同时包含子目录和文件,而子目录又可以包含子目录或者文件。

以下是一个使用Java实现组合模式的示例代码,其中我们使用一个抽象类Component来表示树形结构中的节点,包括叶节点和组合节点。组合节点包含子节点,可以通过add()和remove()方法来添加和删除子节点。叶节点没有子节点,但可以实现共同的操作方法。具体的组合节点继承自Component类,实现自己的操作方法。

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
70
71
72
73
public interface IComponent {
void display();
}

// Component.java
public abstract class Component implements IComponent {
protected String name;

public Component(String name) {
this.name = name;
}

public abstract void add(IComponent component);

public abstract void remove(IComponent component);

}
// Composite.java
public class Composite extends Component {
private List<IComponent> children = new ArrayList<>();

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

@Override
public void add(IComponent component) {
children.add(component);
}

@Override
public void remove(IComponent component) {
children.remove(component);
}

@Override
public void display() {
System.out.println("Composite: " + name);
for (IComponent component : children) {
component.display();
}
}
}
// Leaf.java
public class Leaf implements IComponent {
private String name;

public Leaf(String name) {
this.name = name;
}

@Override
public void display() {
System.out.println("Leaf: " + name);
}
}
// Client.java
public class Client {
public static void main(String[] args) {
Component root = new Composite("root");
Component branch1 = new Composite("branch1");
Component branch2 = new Composite("branch2");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component leaf3 = new Leaf("leaf3");
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch2.add(leaf2);
branch2.add(leaf3);
root.display();
}
}

5.外观模式

定义
为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
应用场景
为一个复杂的模块或子系统提供一个供外界访问的接口。

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
class CPU {
public void processData() {
System.out.println("正在处理数据...");
}
}
class Memory {
public void load() {
System.out.println("正在加载内存...");
}
}
class HardDrive {
public void readData() {
System.out.println("正在读取硬盘数据...");
}
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
cpu = new CPU();
memory = new Memory();
hardDrive = new HardDrive();
}
public void start() {
System.out.println("启动计算机...");
cpu.processData();
memory.load();
hardDrive.readData();
System.out.println("计算机启动完毕!");
}
}
// 客户端代码
public class FacadePatternDemo {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.start();
}
}

6.享元模式

定义
使用共享对象可以有效的支持大量细粒度对象的复用,比如: 池化技术,数据库连接池 、线程池 等
应用场景
系统中存在大量的相似对象
细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对 象没有特定身份。
需要缓冲池的场景

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
class CPU {
public void processData() {
System.out.println("正在处理数据...");
}
}
class Memory {
public void load() {
System.out.println("正在加载内存...");
}
}
class HardDrive {
public void readData() {
System.out.println("正在读取硬盘数据...");
}
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
cpu = new CPU();
memory = new Memory();
hardDrive = new HardDrive();
}
public void start() {
System.out.println("启动计算机...");
cpu.processData();
memory.load();
hardDrive.readData();
System.out.println("计算机启动完毕!");
}
}
// 客户端代码
public class FacadePatternDemo {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.start();
}
}

7.代理模式

定义
封装目标对象,并添加额外的功能,对客户端提供更多更优的服务,分类: 静态代理和动态代理。
应用场景
日志的采集
权限控制
实现aop
Mybatis mapper
Spring的事务全局捕获异常Rpc远程调用接口
分布式事务原理代理数据源

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
/**代理接口*/
public interface IHello {
String hi(String key);
}
/**代理接口实现类*/
public class HelloImpl implements IHello {
@Override
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}
/**静态代理类*/
public class HelloStaticProxy implements IHello {

private IHello hello;

public HelloStaticProxy(IHello hello) {
this.hello = hello;
}

@Override
public String hi(String key) {
System.out.println(">>> static proxy start");
String result = hello.hi(key);
System.out.println(">>> static proxy end");
return result;
}
}
/**测试*/
public class DemoTest {

public static void main(String[] args) {
IHello helloProxy = new HelloStaticProxy(new HelloImpl());
helloProxy.hi("world");
}
}

2)jdk动态代理

jdk动态代理是基于接口的一种代理方式,目标对象一定要实现接口。

原理是,利用反射机制,动态生成匿名类继承Proxy类并且实现了要代理的接口,由于java不支持多继承,所以JDK动态代理不能代理类

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
/**代理接口*/
public interface IHello {
String hi(String key);
}
/**代理接口实现类*/
public class HelloImpl implements IHello {
@Override
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}


/**jdk动态代理类*/
public class JdkProxy implements InvocationHandler {

private Object target;

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

/**
* 获取被代理接口实例对象
*
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>> JdkProxy start");
Object result = method.invoke(target, args);
System.out.println(">>> JdkProxy end");
return result;
}
}

/**测试*/
public class Demo2Test {

public static void main(String[] args) {
JdkProxy proxy = new JdkProxy(new HelloImpl());
IHello helloProxy = proxy.getProxy();
helloProxy.hi(" jdk proxy !");
}
}

目标对象可以不用实现接口,不能针对final类进行代理。
原理是,动态生成class继承目标对象。使用cglib必须引入对应的jar包

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
 <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.7</version>
</dependency>
/**目标类*/
public class HelloImpl {
public String hi(String key) {
String str = "hello:" + key;
System.out.println("HelloImpl! " + str);
return str;
}
}

/**cglib代理类*/
public class CglibProxy implements InvocationHandler {

private Object target;

/**
* 获取被代理接口实例对象
*/
public <T> T getProxy() {
//1创建增强器对象
Enhancer e = new Enhancer();
//2设置增强器的类加载器
e.setClassLoader(target.getClass().getClassLoader());
//3设置代理对象父类类型
e.setSuperclass(target.getClass());
//4设置回调函数
e.setCallback(this);
//5创建代理对象
return (T) e.create();
}

public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>> cglib start");
Object obj = method.invoke(target, args);
System.out.println(">>> cglib end");
return obj;
}
}

/**测试*/
public class Demo3Test {

public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
CglibProxy cglibProxy = new CglibProxy(hello);
HelloImpl proxy = cglibProxy.getProxy();
proxy.hi(" cglib ");
}
}

三、11种行为型模式

模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式。

1.模板方法模式

定义
定义了操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。
应用场景
多个子类有共同的方法,且逻辑基本相同可以把核心的算法和重要的功能设计为模板方法,子类去实现相关细节功能系统在进行重构或者是功能优化的时候可以将子类重复的代码抽离到父类中

下面是一个简单的Java模板模式示例代码:

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
abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
// 模板方法
public final void play() {
// 初始化游戏
initialize();
// 开始游戏
startPlay();
// 结束游戏
endPlay();
}
}
class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}

在上面的代码中,Game类是一个抽象类,定义了一个play()方法作为模板方法。Cricket和Football类是具体的实现类,它们实现了抽象类中定义的抽象方法。在main()方法中,我们创建了一个Cricket对象和一个Football对象,并调用它们的play()方法。这样我们就可以在不改变算法结构的情况下重新定义算法中的某些步骤。

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
37
38
39
40
41
42
43
interface Command {
void execute(String[] args);
}
// 定义具体命令
class CreateFileCommand implements Command {
public void execute(String[] args) {
// 根据给定的名称和内容创建文件的代码
System.out.println("创建文件 : " + String.join(", ", args));
}
}
class DeleteFileCommand implements Command {
public void execute(String[] args) {
// 根据给定的名称删除文件的代码
System.out.println("删除文件 : "+String.join(",",args) );
}
}
// 定义命令执行者
class CommandExecutor {
private Map<String, Command> commands = new HashMap<>();
public CommandExecutor() {
// 将具体命令与命令名称关联起来
commands.put("create", new CreateFileCommand());
commands.put("delete", new DeleteFileCommand());
}
public void executeCommand(String commandName, String[] args) {
// 查找对应的命令并执行
Command command = commands.get(commandName);
if (command != null) {
command.execute(args);
} else {
System.out.println("Unknown command: " + commandName);
}
}
}
// 使用命令执行者执行命令
public class Main {
public static void main(String[] args) {
CommandExecutor executor = new CommandExecutor();
executor.executeCommand("create", new String[]{"file.txt", "Hello World!"});
executor.executeCommand("delete", new String[]{"file.txt"});
executor.executeCommand("unknown", new String[]{});
}
}

执行输出:

1
2
3
创建文件 : file.txt, Hello World!
删除文件 : file.txt
Unknown command: unknown

3.访问者模式

定义
将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式
应用场景
对象结构比较稳定,但经常需要在此对象结构上定义新的操作。需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。

下面是一个简单的Java备忘录模式示例代码:

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
// Originator类表示原始对象,它包含需要保存的状态。
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
// createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。
public Memento createMemento() {
return new Memento(state);
}
// restore()方法用于从备忘录对象中恢复先前的状态。
public void restore(Memento memento) {
state = memento.getState();
}
}
// Memento类表示备忘录对象,它包含需要保存的状态。
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Caretaker类负责管理备忘录对象,它包含一个Memento对象。
class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 保存原始对象的状态到备忘录对象中
originator.setState("State 1");
caretaker.setMemento(originator.createMemento());
// 修改原始对象的状态
originator.setState("State 2");
// 从备忘录对象中恢复先前的状态
originator.restore(caretaker.getMemento());
System.out.println("Current state: " + originator.getState());
}
}

在上面的代码中,Originator类表示原始对象,它包含需要保存的状态。createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。restore()方法用于从备忘录对象中恢复先前的状态。

Memento类表示备忘录对象,它包含需要保存的状态。

Caretaker类负责管理备忘录对象,它包含一个Memento对象。

在main()方法中,我们创建了一个Originator对象和一个Caretaker对象,并调用它们的方法进行状态保存和恢复。通过备忘录模式,我们可以在不破坏封装性的情况下捕获和恢复对象的内部状态。

4.迭代器模式

定义
提供一种方法顺序访问一个聚合对象中各个元素,而又无须暴露该对象的内部表示,提供一种遍历集合元素的统一接口。
应用场景
统一接口:为遍历不同的 集合结构,提供统一接口

下面是一个简单的Java迭代器模式示例代码,使用数组存储,实现了一个数组迭代器:

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
interface Iterator<T> {
boolean hasNext();
T next();
}
// 具体迭代器实现类
class ArrayIterator<T> implements Iterator<T> {
private T[] array;
private int currentIndex;
public ArrayIterator(T[] array) {
this.array = array;
this.currentIndex = 0;
}
public boolean hasNext() {
return currentIndex < array.length;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T element = array[currentIndex];
currentIndex++;
return element;
}
}
// 使用迭代器遍历数组
public class Main {
public static void main(String[] args) {
Integer[] array = {1, 2, 3, 4, 5};
Iterator<Integer> iterator = new ArrayIterator<>(array);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}

在上面的示例代码中,我们定义了抽象迭代器接口(Iterator),用于表示迭代器对象。我们还定义了具体迭代器实现类(ArrayIterator),用于实现数组迭代器。最后,我们使用迭代器遍历了一个整型数组,并打印出了每个元素的值。

5.观察者模式

定义

当一个对象被修改时,则会自动通知依赖它的对象。
观察者,顾名思义,就是一个监听者,类似监听器的存在,一旦被观察/监听的目标发生的情况,就会被监听者发现,这么想来目标发生情况到观察者知道情况,其实是由目标将情况发送到观察者的。
应用场景
多用于实现订阅功能的场景,例如微博的订阅,当我们订阅了某个人的微博账号,当这个人发布了新的消息,就会通知我们。

下面是一个简单的Java观察者模式示例代码,实现了一个气象站,当气象数据发生改变时,会通知所有的观察者对象:

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
70
71
72
import java.util.ArrayList;
import java.util.List;
// 抽象主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体观察者实现类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
private String name;

@Override
public String name() {
return this.name;
}

public Display(String name){
this.name = name;
}

public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}

public void display() {
System.out.println("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}
// 抽象观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
String name();
}
// 具体观察者实现类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
public void display() {
System.out.println("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}
// 使用观察者模式实现气象站
public class Main {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
Display display1 = new Display();
Display display2 = new Display();
weatherStation.registerObserver(display1);
weatherStation.registerObserver(display2);
weatherStation.setMeasurements(25.0f, 60.0f, 1013.0f);
weatherStation.removeObserver(display2);
weatherStation.setMeasurements(26.0f, 65.0f, 1012.0f);
}
}

执行输入结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>> 通知所有观察者 <<
------观察者:01-----------
Temperature: 25.0
Humidity: 60.0
Pressure: 1013.0
------观察者:02-----------
Temperature: 25.0
Humidity: 60.0
Pressure: 1013.0
>> 通知所有观察者 <<
------观察者:01-----------
Temperature: 26.0
Humidity: 65.0
Pressure: 1012.0

在上面的示例代码中,我们定义了抽象主题接口(Subject)和抽象观察者接口(Observer),用于表示主题和观察者对象。我们还定义了具体主题实现类(WeatherStation)和具体观察者实现类(Display),用于实现气象站和显示器对象。最后,我们使用观察者模式实现了一个气象站,当气象数据发生改变时,会通知所有的观察者对象,并更新显示器的数据。

Java自带观察者模式介绍

Java提供的一种内置的观察者模式实现。它使用了Java中的Observable类和Observer接口来实现观察者模式。

Observable类是一个抽象类,它表示一个可观察的对象,具有添加、删除和通知观察者的方法。当Observable对象的状态发生改变时,会调用它的notifyObservers()方法,通知所有的观察者对象,并更新它们的状态。Observable类还提供了setChanged()方法和clearChanged()方法,用于标记Observable对象的状态是否发生了改变。

Observer接口表示观察者对象,具有更新状态的方法update()。当Observable对象的状态发生改变时,会调用观察者对象的update()方法,传递更新的数据。

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
import java.util.Observable;
import java.util.Observer;

// 具体主题类
class WeatherStation extends Observable {
private float temperature;
private float humidity;
private float pressure;

public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
setChanged();
notifyObservers();
}

public float getTemperature() {
return temperature;
}

public float getHumidity() {
return humidity;
}

public float getPressure() {
return pressure;
}
}

// 具体观察者类
class Display implements Observer {
private float temperature;
private float humidity;
private float pressure;

public void update(Observable o, Object arg) {
if (o instanceof WeatherStation) {
WeatherStation weatherStation = (WeatherStation) o;
this.temperature = weatherStation.getTemperature();
this.humidity = weatherStation.getHumidity();
this.pressure = weatherStation.getPressure();
display();
}
}

public void display() {
System.out.println("Temperature: " + temperature);
System.out.println("Humidity: " + humidity);
System.out.println("Pressure: " + pressure);
}
}

// 使用JDK自带观察者模式实现气象站
public class Main {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
Display display1 = new Display();
Display display2 = new Display();
weatherStation.addObserver(display1);
weatherStation.addObserver(display2);
weatherStation.setMeasurements(25.0f, 60.0f, 1013.0f);
weatherStation.deleteObserver(display2);
weatherStation.setMeasurements(26.0f, 65.0f, 1012.0f);
}
}

在上面的示例代码中,我们使用了Observable类和Observer接口来实现气象站和显示器对象。当气象数据发生改变时,Observable对象会调用notifyObservers()方法,通知所有的观察者对象,并更新它们的状态。观察者对象实现Observer接口的update()方法,用于更新自己的状态。

6.中介者模式

定义
是用来降低多个对象和类之间的通信复杂性,这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松合,使代码易于维护
应用场景
当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的具体中介者类。

下面是一个简单的Java中介者模式示例代码:

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
70
71
72
// Mediator接口定义了send()方法,用于处理对象之间的交互。
interface Mediator {
void send(String message, Colleague colleague);
}
// Colleague抽象类表示对象,它包含一个Mediator对象,用于处理对象之间的通信。
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
public abstract void send(String message);
}
// ConcreteColleague1和ConcreteColleague2是具体的对象实现类,它们实现了Colleague抽象类中的方法。
class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
@Override
public void receive(String message) {
System.out.println("Colleague1 received message: " + message);
}
@Override
public void send(String message) {
System.out.println("Colleague1 sends message: " + message);
mediator.send(message, this);
}
}
class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
@Override
public void receive(String message) {
System.out.println("Colleague2 received message: " + message);
}
@Override
public void send(String message) {
System.out.println("Colleague2 sends message: " + message);
mediator.send(message, this);
}
}
// ConcreteMediator是具体的中介者实现类,它负责协调对象之间的通信。
class ConcreteMediator implements Mediator {
private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;
public void setColleague1(ConcreteColleague1 colleague1) {
this.colleague1 = colleague1;
}
public void setColleague2(ConcreteColleague2 colleague2) {
this.colleague2 = colleague2;
}
@Override
public void send(String message, Colleague colleague) {
if (colleague == colleague1) {
colleague2.receive(message);
} else {
colleague1.receive(message);
}
}
}
public class MediatorPatternDemo {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.send("Hello, Colleague2.");
colleague2.send("Hello, Colleague1.");
}
}

在上面的代码中,Mediator接口定义了send()方法,用于处理对象之间的交互。Colleague抽象类表示对象,它包含一个Mediator对象,用于处理对象之间的通信。ConcreteColleague1和ConcreteColleague2是具体的对象实现类,它们实现了Colleague抽象类中的方法。ConcreteMediator是具体的中介者实现类,它负责协调对象之间的通信。

在main()方法中,我们创建了一个ConcreteMediator对象和两个ConcreteColleague对象,并调用它们的send()方法进行通信。通过中介者对象进行通信,避免了对象之间的直接耦合。

7.备忘录模式

定义
所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
应用场景
需要保存和恢复数据的相关状态场景
Windows 里的 ctri + z
E 中的后退。
数据库连接的事务管理就是用的备忘录模式

下面是一个简单的Java备忘录模式示例代码:

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
// Originator类表示原始对象,它包含需要保存的状态。
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
// createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。
public Memento createMemento() {
return new Memento(state);
}
// restore()方法用于从备忘录对象中恢复先前的状态。
public void restore(Memento memento) {
state = memento.getState();
}
}
// Memento类表示备忘录对象,它包含需要保存的状态。
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Caretaker类负责管理备忘录对象,它包含一个Memento对象。
class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 保存原始对象的状态到备忘录对象中
originator.setState("State 1");
caretaker.setMemento(originator.createMemento());
// 修改原始对象的状态
originator.setState("State 2");
// 从备忘录对象中恢复先前的状态
originator.restore(caretaker.getMemento());
System.out.println("Current state: " + originator.getState());
}
}

在上面的代码中,Originator类表示原始对象,它包含需要保存的状态。createMemento()方法创建备忘录对象,并将当前状态保存到备忘录对象中。restore()方法用于从备忘录对象中恢复先前的状态。

Memento类表示备忘录对象,它包含需要保存的状态。

Caretaker类负责管理备忘录对象,它包含一个Memento对象。

在main()方法中,我们创建了一个Originator对象和一个Caretaker对象,并调用它们的方法进行状态保存和恢复。通过备忘录模式,我们可以在不破坏封装性的情况下捕获和恢复对象的内部状态。

8.解释器模式

定义
这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL解析、符号处理引擎等.
应用场景
重复发生的问题可以使用解释器模式
例如,多个应用服务器,每天产生大量的日志,需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,但是非终结符表达式就需要制定了。在这种情况下,可以通过程序来一劳永逸地解决该问题

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
interface Expression {
int interpret(Context context);
}
// 终结符表达式
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 上下文
class Context {
private Map<String, Integer> variables = new HashMap<>();
public void setVariable(String name, int value) {
variables.put(name, value);
}
public int getVariable(String name) {
return variables.get(name);
}
}
// 解释器
class Interpreter {
private Expression expression;
public Interpreter(Expression expression) {
this.expression = expression;
}
public int interpret(Context context) {
return expression.interpret(context);
}
}
// 使用解释器执行表达式
public class Main {
public static void main(String[] args) {
// 创建上下文
Context context = new Context();
context.setVariable("a", 10);
context.setVariable("b", 20);
// 创建表达式
Expression expression = new AddExpression(
new NumberExpression(context.getVariable("a")),
new NumberExpression(context.getVariable("b"))
);
// 创建解释器并执行表达式
Interpreter interpreter = new Interpreter(expression);
int result = interpreter.interpret(context);
System.out.println("Result: " + result);
}
}

在上面的示例代码中,我们定义了两个终结符表达式(NumberExpression)和一个非终结符表达式(AddExpression),用于表示加法操作。我们还定义了一个上下文(Context),用于存储变量和函数,以及一个解释器(Interpreter),用于执行表达式。最后,我们使用解释器执行了一个简单的加法表达式,并打印出了结果。

9.状态模式

定义
我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类
应用场景
行为随状态改变而改变的场景这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行 为结果也会不同,在这种情况下需要考虑使用状态模式QQ的不同状态可以用状态模式来处理,包括离线,登录中,在线和忙碌

下面是一个使用Java状态模式实现的示例代码:

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
interface State {
void handle();
}
// 具体状态类1
class ConcreteState1 implements State {
public void handle() {
System.out.println("ConcreteState1 is handling.");
}
}
// 具体状态类2
class ConcreteState2 implements State {
public void handle() {
System.out.println("ConcreteState2 is handling.");
}
}
// 环境类
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
// 使用状态模式实现的客户端代码
public class Main {
public static void main(String[] args) {
Context context = new Context();
State state1 = new ConcreteState1();
State state2 = new ConcreteState2();
context.setState(state1);
context.request();
context.setState(state2);
context.request();
}
}

在上面的示例代码中,我们定义了一个状态接口State和两个具体状态类ConcreteState1和ConcreteState2。我们还定义了一个环境类Context,它包含一个状态对象,并定义了一个请求方法request(),用于调用当前状态对象的handle()方法。在客户端代码中,我们创建了一个Context对象,并设置它的状态为ConcreteState1,然后调用request()方法,输出”ConcreteState1 is handling.“。接着,我们将Context的状态设置为ConcreteState2,并再次调用request()方法,输出”ConcreteState2 is handling.”。

通过使用状态模式,我们可以将状态和行为分离,使得对象的行为可以随着状态的改变而改变,从而实现更加灵活的设计。

10.策略模式

定义
利用面向对象的多态特点,引用的是抽象父类,当实际调用的时候是该对象的实体子类,从而调用不同的逻辑
应用场景
诸葛亮的锦囊妙计,每一个锦囊就是一个策略旅行的出游方式,选择骑自行车.坐汽车,每一种旅行方式都是一个策略

下面的例子展示了如何使用策略模式来实现一个简单的支付系统。我们定义了一个接口 PaymentStrategy ,并创建了多个实现该接口的类,每个类代表一种不同的支付方式。客户端可以根据需要选择使用哪种支付方式。

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
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cvv;
private String expiryDate;
public CreditCardPayment(String cardNumber, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " using credit card.");
}
}
class PayPalPayment implements PaymentStrategy {
private String email;
private String password;
public PayPalPayment(String email, String password) {
this.email = email;
this.password = password;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " using PayPal.");
}
}
class CashPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paying " + amount + " using cash.");
}
}
class PaymentProcessor {
private PaymentStrategy strategy;
public PaymentProcessor(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processPayment(double amount) {
strategy.pay(amount);
}
}
public class PaymentSystem {
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor(new CreditCardPayment("1234 5678 9012 3456", "123", "12/23"));
processor.processPayment(100.0);
processor.setStrategy(new PayPalPayment("example@example.com", "password"));
processor.processPayment(50.0);
processor.setStrategy(new CashPayment());
processor.processPayment(25.0);
}
}

执行输出:

1
2
3
Paying 100.0 using credit card.
Paying 50.0 using PayPal.
Paying 25.0 using cash.

11.责任链模式

定义
责任链模式:在这种模式中,通常每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推
应用场景
多个对象可以处理同一个请求,但具体由哪个对象处理则在运行时动态决定。JAVA WEB 中 Apache Tomcat 对 Encoding 的处理Struts2的拦截器Servlet 的 Filter实现

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
70
71
72
73
74
75
public interface Handler {
Handler setNextHandler(Handler nextHandler);
void handleRequest(Request request);
}
// 创建抽象处理器类
public abstract class AbstractHandler implements Handler {
private Handler nextHandler;

public Handler setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
return this.nextHandler;
}

public Handler getNextHandler() {
return nextHandler;
}
}

// 创建具体的处理器类
public class ConcreteHandler1 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type1")) {
System.out.println("ConcreteHandler1 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
public class ConcreteHandler2 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type2")) {
System.out.println("ConcreteHandler2 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
public class ConcreteHandler3 extends AbstractHandler {
public void handleRequest(Request request) {
if (request.getType().equals("Type3")) {
System.out.println("ConcreteHandler3 handles request " + request);
} else {
getNextHandler().handleRequest(request);
}
}
}
// 创建请求类
public class Request {
private String type;

public Request(String type) {
this.type = type;
}

public String getType() {
return type;
}

public String toString() {
return "Request [type=" + type + "]";
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2)
.setNextHandler(handler3);
handler1.handleRequest(new Request("Type1"));
handler1.handleRequest(new Request("Type2"));
handler1.handleRequest(new Request("Type3"));
}
}

输入结果:

1
2
3
ConcreteHandler1 handles request Request [type=Type1]
ConcreteHandler2 handles request Request [type=Type2]
ConcreteHandler3 handles request Request [type=Type3]

以上代码演示了如何创建一个处理器链,并将请求沿着链传递,直到有一个处理程序处理它为止。在这个例子中,ConcreteHandler1、ConcreteHandler2和ConcreteHandler3都是具体的处理器类,它们继承自AbstractHandler类,并实现handleRequest方法。客户端代码创建了一个处理器链,并将请求发送到链的第一个处理器。当请求到达处理器时,它会检查请求类型是否与处理器可以处理的类型匹配。如果是,处理器将处理请求。否则,它将请求传递给链中的下一个处理器,直到有一个处理程序处理它为止。

  • 标题: Java23种设计模式
  • 作者: 小颜同学
  • 创建于: 2023-07-26 10:24:18
  • 更新于: 2023-12-18 09:06:28
  • 链接: https://www.wy-studio.cn/2023/07/26/Java23种设计模式/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论