设计模式

SOLID

  1. 单一职责原则(Single Responsibility Principle,SRP):一个类只负责单一的功能,避免一个类承担过多的职责,从而提高代码的可维护性。
  2. 开放封闭原则(Open Closed Principle,OCP):软件实体应该对扩展开放,对修改关闭,也就是说,应该通过增加代码而不是修改代码来扩展软件功能,从而提高代码的可维护性和扩展性。
  3. 里氏替换原则(Liskov Substitution Principle,LSP):子类应该能够替换父类并且不影响程序的正确性,也就是说,子类必须能够完全实现父类的功能,从而提高代码的可扩展性。
  4. 接口隔离原则(Interface Segregation Principle,ISP):客户端不应该依赖于它不需要的接口,也就是说,应该尽量将接口细化,将不同的功能分离开来,从而提高代码的灵活性和可复用性。
  5. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖于低层模块,它们应该依赖于抽象,而不是具体实现,也就是说,应该通过接口或者抽象类来实现模块之间的松耦合,从而提高代码的可维护性和可扩展性。

找出会变的地方,把他们从不变的地方抽离出来(策略模式运用了)

策略模式

不同的算法或行为封装成独立的策略对象,使它们可以相互替换,从而使系统更加灵活和可扩展。

提高代码的可复用性和可维护性:

  • 如果每一个上下文都有该方法,我只需要设置成员变量即可,代码都写在策略中。不同的策略实现不同的方法
    • 如果使用继承去获得该策略,那么有的上下文他不需要(有的鸭子不会叫)就需要覆盖
    • 如果使用接口,接口可以扩展上下文,但每一个上下文都需要实现同样的方法,代码没有复用
    • 拉取出变化的部分,重新建立一个类,并针对接口编程。最后把拉出来的作为成员变量插入

实现过程:

  1. 策略接口:定义一个抽象策略接口,该接口定义了算法的公共方法。(Fly)
  2. 具体策略:然后针对每种算法,创建一个具体的策略类,实现该接口。(FlyWings、NoWay)
  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
// 抽象策略接口
interface SortingStrategy {
void sort(int[] array);
}

// 具体策略类1
class BubbleSort implements SortingStrategy {
public void sort(int[] array) {
// Bubble sort implementation
}
}

// 具体策略类2
class QuickSort implements SortingStrategy {
public void sort(int[] array) {
// Quick sort implementation
}
}

// 上下文类
class SortingContext {
private SortingStrategy strategy;

public void setStrategy(SortingStrategy strategy) {
this.strategy = strategy;
}

public void sort(int[] array) {
strategy.sort(array);
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
int[] array = {5, 2, 8, 4, 7};
SortingContext context = new SortingContext();

// 使用冒泡排序
context.setStrategy(new BubbleSort());
context.sort(array);

// 使用快速排序
context.setStrategy(new QuickSort());
context.sort(array);
}
}

观察者模式

一(主题)对多(观察者);主题变化时需要通知所有人

普通写法

1
2
3
4
5
6
{
person1.update();
person2.update();
...
// 如果加入新对象,该函数代码需要进行修改
}

观察者模式:定义一个数组保存全部Observe,观察者在创建时加入主题数组,主题在变化时通知数组全部人

​ 我想要数组中每一个不同的观察者统一调用同一个函数,自然而然想到使用接口。

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
// 主题接口
interface Subject {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(); // 通知观察者
// 具体实现
@Override
public void notifyObservers() {
for (Observer observer : observers) { // 通知所有人
observer.update(temperature, humidity, pressure);
}
}
}


// 观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure); // 更新状态
}
// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private Subject weatherData;

public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this); // 注册加入
}

”趣学架构“中的非主链路的统计、打点,使用观察者模式实现

装饰者模式

装饰器类将对象包装,通过构造函数传递给装饰器;装饰器和被装饰对象需要实现相同的接口,并在实现中进行叠加

1
2
3
4
5
6
public Decorator(Beverage beverage) {
this.beverage = beverage; // 构造函数传递被装饰对象
}
public double getCost() {
return beverage.getCost() + 0.10; // 叠加使用
}
  • 允许你在运行时动态地扩展一个对象的功能。
  • 组合而非继承
  • 包装原始对象而不影响其原始结构和行为(通过成员变量引用访问到原始对象has-a的关系)
  1. 抽象组件(Component):定义了被装饰者和装饰者的共同接口。
  2. 具体组件(ConcreteComponent):实现了抽象组件接口,并定义了被装饰者的基本行为。
  3. 抽象装饰者(Decorator):定义了装饰者的接口,并持有一个被装饰者的引用。has-a
  4. 具体装饰者(ConcreteDecorator):实现了抽象装饰者的接口,并向被装饰者添加新的行为和责任。

image-20230422155809934

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
// 抽象组件
interface Beverage {
String getDescription();
double getCost();
}

// 具体组件
class Espresso implements Beverage {
public String getDescription() {
return "Espresso";
}

public double getCost() {
return 1.99;
}
}

// 装饰者
abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;

public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription();
}

public abstract double getCost();
}

// 具体装饰者
class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}

public String getDescription() {
return beverage.getDescription() + ", Milk";
}

public double getCost() {
return beverage.getCost() + 0.10;
}
}

class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}

public String getDescription() {
return beverage.getDescription() + ", Mocha";
}

public double getCost() {
return beverage.getCost() + 0.20;
}
}

// 测试代码
public class Test {
public static void main(String[] args) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.getCost());

Beverage beverage2 = new Espresso();
beverage2 = new Milk(beverage2);
beverage2 = new Mocha(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.getCost());
}
}

// 在此基础上,我还想添加满减、九折等,同样是定义一个ConcreteDecorator即可 beverage.getCost()*0.9

Java I/O库

SQL查询通常由多个组件构成,如SELECT、FROM、WHERE、JOIN等。我们可以使用装饰者模式来构建这些组件,并动态地添加额外的功能,例如缓存、日志记录等。 Filter 和 SeqScan的关系

单例模式

全局变量可以提供全局访问,但不能确保唯一。

public的类,但private的构造方法,通过static方法访问private构造方法,构造一个static变量

饿汉模式

全局直接初始化

1
2
3
4
5
6
7
8
9
public class Singleton {
private static Singleton instance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
return instance;
}
}

懒汉模式

synchronized

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {
private static Singleton instance;

private Singleton() {}

public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

双重检查

volatile:强制立即写入内存,并强制内存读取,而不是缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private static volatile Singleton instance;

private Singleton() {}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

享元模式

共享对象来减少内存使用和提高性能

字符串池、Integer常量池、数据库连接池

状态模式

当一个对象的行为取决于其状态,并且它必须在运行时根据状态改变其行为时。

订单处理系统:订单有多种状态,如新建订单、已支付、已发货、已收货、已完成等。每种状态下,订单可以执行的操作都可能不同。

以下是一个基于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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// 状态接口
interface OrderState {
void next(Order order);
void prev(Order order);
void printStatus();
}

// 具体状态类
class New implements OrderState {
public void next(Order order) {
order.setState(new Paid());
}

public void prev(Order order) {
System.out.println("The order is in its root state.");
}

public void printStatus() {
System.out.println("New order.");
}
}

class Paid implements OrderState {
public void next(Order order) {
order.setState(new Shipped());
}

public void prev(Order order) {
order.setState(new New());
}

public void printStatus() {
System.out.println("Order paid.");
}
}

class Shipped implements OrderState {
public void next(Order order) {
order.setState(new Delivered());
}

public void prev(Order order) {
order.setState(new Paid());
}

public void printStatus() {
System.out.println("Order shipped.");
}
}

class Delivered implements OrderState {
public void next(Order order) {
System.out.println("This order is already delivered.");
}

public void prev(Order order) {
order.setState(new Shipped());
}

public void printStatus() {
System.out.println("Order delivered.");
}
}

// 上下文类
class Order {
private OrderState state;

public Order() {
this.state = new New();
}

public void setState(OrderState state) {
this.state = state;
}

public void next() {
state.next(this);
}

public void prev() {
state.prev(this);
}

public void printStatus() {
state.printStatus();
}
}

// 客户端代码
public class Main {
public static void main(String[] args) {
Order order = new Order();

order.printStatus(); // 输出: New order.

order.next();
order.printStatus(); // 输出: Order paid.

order.next();
order.printStatus(); // 输出: Order shipped.

order.prev();
order.printStatus(); // 输出: Order paid.
}
}

在这个例子中,OrderState接口定义了nextprevprintStatus三个方法,表示订单的下一个状态、上一个状态和打印当前状态。NewPaidShippedDelivered类分别实现了OrderState接口,代表了订单的四种状态。Order类就是所谓的上下文,它持有一个OrderState对象,代表当前的状态。

模板方法模式

定义一个操作中的骨架,标准化流程

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
import com.google.common.base.Stopwatch;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

public abstract class ServiceTemplate<T, R> {
private final Logger logger = new LoggerImpl();

/**
* 模板统一暴露执行入口
*/
public R process(T request) {
// 1.打印入口日志
logger.info("start invoke, request=" + request);
// 开始计时,用于日志记录耗时
Stopwatch stopwatch = Stopwatch.createStarted();
try {
// 2. 校验参数
validParam(request);
// 3. 子类实现逻辑
R response = doProcess(request);
// 4.打印出口日志
long timeCost = stopwatch.elapsed(TimeUnit.MILLISECONDS);
logger.info("end invoke, response=" + response + ", costTime=" + timeCost);
return response;
} catch (Exception e) {
// 打印异常日志
logger.error("error invoke, exception:" + Arrays.toString(e.getStackTrace()));
return null;
}
}

/**
* 参数校验(交给子类实现)
*/
protected abstract void validParam(T request);

/**
* 执行业务逻辑(交给子类实现)
*/
protected abstract R doProcess(T request);
}

责任链

image-20240118172157467

责任链:沿着这条链传递请求,直到有一个对象处理它为止,具体由哪个对象处理则在运行时动态决定的情况。

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
abstract class Handler {
protected Handler successor;

public void setSuccessor(Handler successor) {
this.successor = successor;
}

public abstract void handleRequest(double amount);
}

class NoDiscountHandler extends Handler {
public void handleRequest(double amount) {
System.out.println("No discount applied.");
}
}

class LowDiscountHandler extends Handler {
public void handleRequest(double amount) {
if (amount < 1000) {
System.out.println("Low discount applied. Amount: " + amount);
} else if (successor != null) {
successor.handleRequest(amount);
}
}
}

class HighDiscountHandler extends Handler {
public void handleRequest(double amount) {
if (amount >= 1000) {
System.out.println("High discount applied. Amount: " + amount);
} else if (successor != null) {
successor.handleRequest(amount);
}
}
}

class HandlerChain {
private Handler head;
private Handler tail;

public HandlerChain add(Handler handler) {
if (head == null) {
head = handler;
tail = handler;
} else {
tail.setSuccessor(handler);
tail = handler;
}
return this;
}

public void handleRequest(double amount) {
if (head != null) {
head.handleRequest(amount);
}
}
}

public class ChainDemo {
public static void main(String[] args) {
HandlerChain chain = new HandlerChain();
chain.add(new LowDiscountHandler())
.add(new HighDiscountHandler())
.add(new NoDiscountHandler());

// Making requests
chain.handleRequest(500);
chain.handleRequest(1500);
}
}

流程引擎

见 ”趣学架构“