大话设计模式

本文最后更新于:2024年5月19日 凌晨

大话设计模式

此文为我学习大话设计模式时的笔记,代码样例也是书里的。这本书对学习理解设计模式还是挺有帮助,推荐大家可以看看~

第 0 章 面向对象基础

1. 类与实例

万物皆对象,对象是一个自包含的实体,用一组可识别的特性和行为来标识。

类就是具有相同的属性和功能的对象的抽象的集合。

实例,就是一个真实的对象。而实例化就是创建对象的过程,使用new关键字来创建。

2. 构造方法

构造方法,又叫构造函数,其实就是对类进行初始化。构造方法与类同名,无返回值,也不需要void,在 new 的使用调用。

所有类都有构造方法,如果你不编码则系统默认生成空的构造方法,若你有定义的构造方法,那么默认的构造方法就会失效了。

3. 方法重载

方法重载提供了创建同名的多个方法的能力,但这些方法需使用不同的参数类型。

方法重载时,需方法名相同,但参数类型或个数必须要有所不同。

方法重载可在不改变原方法的基础上,新增功能。

4. 属性与修饰符

属性是一个方法或一对方法,即属性适合于以字段的方式使用方法调用的场合。

字段是存储类要满足其设计所需要的数据,字段是与类相关的变量。

5. 封装

每个对象都包含它能进行操作所需要的所有信息,这个特性称为封装,因此对象不必依赖其他对象来完成自己的操作。

封装有多个好处:

  • 良好的封装能够减少耦合。
  • 类内部的实现可以自由地修改。
  • 类具有清晰的对外接口。

6. 继承

对象的继承代表了一种‘is-a’的关系,如果两个对象A和B,可以描述为‘B是A’,则表明B可以继承A。

继承者还可以理解为是对被继承者的特殊化,因为它除了具备被继承者的特性外,还具备自己独有的个性。

继承定义了类如何相互关联,共享特性。

继承的工作方式是:定义父类和子类,或叫作基类和派生类,其中子类继承父类的所有特性。

子类不但继承了父类的所有特性,还可以定义新的特性。

如果子类继承与父类:

  • 子类拥有父类非 private 的属性和功能
  • 子类具有自己的属性和功能,即子类可以扩展父类没有的属性和功能
  • 子类还可以以自己的方式实现父类的功能(方法重写)

第 1 章 简单工厂模式

题目:请用C++、Java、C#或Python等任意一种面向对象语言实现一个计算器控制台程序,要去输入两个数和运算符号,得到结果。

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

/**
* @author 顾梦
* @create 2023/4/24
* 简单工厂模式 实现简单计算器
*/
public class SimpleFactory {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

System.out.println("请输入数字A: ");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/): ");
String strOperate = sc.nextLine();
System.out.println("请输入数字B: ");
double numberB = Double.parseDouble(sc.nextLine());

Operation operate = OperationFactory.createOperate(strOperate);
double result = operate.getResult(numberA, numberB);

System.out.println("结果是: " + result);
}
}

class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}

abstract class Operation {
public double getResult(double numberA, double numberB) {
return 0d;
}
}

class Add extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}

class Sub extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}

class Mul extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA * numberB;
}
}

class Div extends Operation {
@Override
public double getResult(double numberA, double numberB) {
if (numberB == 0) {
System.out.println("除数不能为0");
throw new ArithmeticException();
}
return numberA / numberB;
}
}

第 2 章 策略模式

策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import java.util.*;
/**
* @author 顾梦
* @create 2023/4/27
* 策略模式 解决商场收银问题
*/

public class StrategyPattern {
public static void main(String[] args) {

double price = 0d; // 商品单价
int num = 0; // 商品购买数量
double totalPrices = 0d; // 当前商品合计费用
double total = 0d; // 总计所有商品费用

Scanner sc = new Scanner(System.in);
do {
System.out.println("请输入商品销售模式 1.原价 2.八折 3.满300返100");
int discount = Integer.parseInt(sc.nextLine());
System.out.println("请输入商品单价:");
price = Double.parseDouble(sc.nextLine());
System.out.println("请输入商品数量:");
num = Integer.parseInt(sc.nextLine());
System.out.println();

if (price > 0 && num > 0){
CashContext cc = new CashContext(discount);
totalPrices = cc.getResult(price, num);
total = total + totalPrices;

System.out.println();
System.out.println("单价:" + price +"元,数量:" + num + " 合计:" + totalPrices + "元");
System.out.println();
System.out.println("总计:" + total + "元");
System.out.println();
}

}while (price > 0 && num > 0);

}
}

// 收费抽象类
abstract class CashSuper{

// 收取费用的抽象方法,参数为单价和数量
public abstract double acceptCash(double price,int num);
}

// 正常收费
class CashNormal extends CashSuper{

@Override
public double acceptCash(double price, int num) {
return price * num;
}
}

class CashRebate extends CashSuper{

private double moneyRebate = 1d;

// 初始化时必须输入折扣率。八折就输入0.8
public CashRebate(double moneyRebate){
this.moneyRebate = moneyRebate;
}

// 计算收费时需要在原价基础上乘以折扣率
@Override
public double acceptCash(double price, int num) {
return price * num * this.moneyRebate;
}
}

class CashReturn extends CashSuper{

private double moneyCondition = 0d; // 返利条件
private double moneyReturn = 0d; // 返利值

// 返利收费。初始化时需要输入返利条件和返利值。
// 比如"满300返100",就是moneyCondition=300,moneyReturn100
public CashReturn(double moneyCondition, double moneyReturn) {
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}

// 计算收费时,当达到返利条件,就原价减去返利值
@Override
public double acceptCash(double price, int num) {
double result = price * num;
if (moneyCondition > 0 && price >= moneyCondition){
result = result - Math.floor(result / moneyCondition) * moneyReturn;
}
return result;
}
}

class CashContext{
private CashSuper cs; // 声明一个CashSuper对象

// 通过构造方法,传入具体的收费策略
// public CashContext(CashSuper csuper){
// this.cs = csuper;
// }

// 结合简单工厂模式
public CashContext(int cashType){
switch (cashType){
case 1:
this.cs = new CashNormal();
break;
case 2:
this.cs = new CashRebate(0.8d);
break;
case 3:
this.cs = new CashReturn(300d,100d);
break;
}
}

public double getResult(double price, int num) {
// 根据收费策略的不同,获得计算结果
return this.cs.acceptCash(price, num);
}
}

第 3 章 单一职责原则

单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因。

  • 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
  • 软件设计真正要做的许多内容,就是发现职责并把那么些职责相互分离。
  • 如果你能够想到多于一个的动机去改变一个类,那么这个类就是具有多于一个的职责。

第 4 章 开放-封闭原则

开放-封闭原则,是说软件实体(类、模块、函数等)应该可以扩展,但是不可修改。

  • 对于扩展是开放的(Open for extension)
  • 对于修改是封闭的(Closed for modification)

开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。

第 5 章 依赖倒转原则

依赖倒转原则:

  • 高层模块不应该依赖低层模块。两个都应该依赖抽象。
  • 抽象不应该依赖细节。细节应该依赖抽象。

里氏代换原则(LSP):子类型必须能够替换掉它们的父类型。

由于子类型的可替换性才使得使用父类类型的模块在无须修改的情况下就可以扩展。

第 6 章 装饰模式

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

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
/**
* @author 顾梦
* @create 2023/4/28
* 装饰模式
*/

public class DecoratorPattern {

public static void main(String[] args) {
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();

d1.SetComponent(c); // 首先用d1来包装c
d2.SetComponent(d1); // 再用d2来包装d1
d2.Operation(); // 最终执行d2的Operation()
}
}

abstract class Component{
public abstract void Operation();
}

class ConcreteComponent extends Component{
public void Operation(){
System.out.println("具体对象的实际操作");
}
}

abstract class Decorator extends Component{
protected Component component;

// 装饰一个Component 对象
public void SetComponent(Component component){
this.component = component;
}

// 重写Operation(),实际调用component的Operation方法
@Override
public void Operation() {
if (component != null){
component.Operation();;
}
}
}

class ConcreteDecoratorA extends Decorator{

protected String addedState; // 本类独有字字段,以区别于ConcreteDecoratorB类

public void Operation(){
super.Operation(); // 首先运行了原有Component的Operation()

this.addedState = "具有装饰对象A的独有操作"; // 再执行本类独有的功能
System.out.println(this.addedState);

}
}

class ConcreteDecoratorB extends Decorator{

public void Operation(){
super.Operation(); // 首先运行了原有Component的Operation()
this.AddedBehavior(); // 再执行本类独有功能
}

// 本类独有方法,以区别于ConcreteDecoratorA类
private void AddedBehavior(){
System.out.println("具有装饰对象B的独有操作");
}
}

商场促销——简单工厂+策略+装饰模式实现

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package cn.jishuin;

import java.util.*;

/**
* @author 顾梦
* @create 2023/4/28
* 商场促销——简单工厂+策略+装饰模式
*/
public class Promotion {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();

int discount = 0; //商品折扣模式
double price = 0d; //商品单价
int num = 0; //商品购买数量
double totalPrices = 0d;//当前商品合计费用
double total = 0d; //总计所有商品费用

Scanner sc = new Scanner(System.in);

do {
System.out.println("商品折扣模式如下:");
System.out.println("1.正常收费");
System.out.println("2.打八折");
System.out.println("3.打七折");
System.out.println("4.满300送100");
System.out.println("5.先打8折,再满300送100");
System.out.println("6.先满200送50,再打7折");
System.out.println("请输入商品折扣模式:");
discount = Integer.parseInt(sc.nextLine());
System.out.println("请输入商品单价:");
price = Double.parseDouble(sc.nextLine());
System.out.println("请输入商品数量:");
num = Integer.parseInt(sc.nextLine());
System.out.println();

if (price>0 && num>0){

//根据用户输入,将对应的策略对象作为参数传入CashContext对象中
CashContext cc = new CashContext(discount);

//通过Context的getResult方法的调用,可以得到收取费用的结果
//让具体算法与客户进行了隔离
totalPrices = cc.getResult(price,num);

total = total + totalPrices;

System.out.println();
System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ totalPrices +"元");
System.out.println();
System.out.println("总计:"+ total+"元");
System.out.println();
}
}
while(price>0 && num>0);

System.out.println();
System.out.println("**********************************************");
}
}

interface ISale {
double acceptCash(double price,int num);
}

class CashSuper implements ISale {

protected ISale component;

//装饰对象
public void decorate(ISale component) {
this.component=component;
}

public double acceptCash(double price,int num){

double result = 0d;
if (this.component != null){
//若装饰对象存在,则执行装饰的算法运算
result = this.component.acceptCash(price,num);
}
return result;

}

}


class CashNormal implements ISale {
//正常收费,原价返回
public double acceptCash(double price,int num){
return price * num;
}
}


class CashRebate extends CashSuper {

private double moneyRebate = 1d;
//打折收费。初始化时必需输入折扣率。八折就输入0.8
public CashRebate(double moneyRebate){
this.moneyRebate = moneyRebate;
}

//计算收费时需要在原价基础上乘以折扣率
public double acceptCash(double price,int num){
double result = price * num * this.moneyRebate;
return super.acceptCash(result,1);
}

}

class CashReturn extends CashSuper {

private double moneyCondition = 0d; //返利条件
private double moneyReturn = 0d; //返利值

//返利收费。初始化时需要输入返利条件和返利值。
//比如“满300返100”,就是moneyCondition=300,moneyReturn=100
public CashReturn(double moneyCondition,double moneyReturn){
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}

//计算收费时,当达到返利条件,就原价减去返利值
public double acceptCash(double price,int num){
double result = price * num;
if (moneyCondition>0 && result >= moneyCondition)
result = result - Math.floor(result / moneyCondition) * moneyReturn;
return super.acceptCash(result,1);
}

}

class CashContext {
private ISale cs; //声明一个ISale接口对象

//通过构造方法,传入具体的收费策略
public CashContext(int cashType) {
switch (cashType) {
case 1:
this.cs = new CashNormal();
break;
case 2:
CashRebate cr1 = new CashRebate(0.7d);
cr1.decorate(new CashNormal());
this.cs = cr1;
break;
case 3:
CashRebate cr2 = new CashRebate(0.8d);
cr2.decorate(new CashNormal());
this.cs = cr2;
break;
case 4:
CashReturn cr3 = new CashReturn(300d, 100d);
cr3.decorate(new CashNormal());
this.cs = cr3;
break;
case 5:
//先打8折,再满300返100
CashNormal cn = new CashNormal();
CashReturn cr4 = new CashReturn(300d, 100d);
CashRebate cr5 = new CashRebate(0.8d);
cr4.decorate(cn); //用满300返100算法包装基本的原价算法
cr5.decorate(cr4); //打8折算法装饰满300返100算法
this.cs = cr5; //将包装好的算法组合引用传递给cs对象
break;
case 6:
//先满200返50,再打7折
CashNormal cn2 = new CashNormal();
CashRebate cr6 = new CashRebate(0.7d);
CashReturn cr7 = new CashReturn(200d, 50d);
cr6.decorate(cn2); //用打7折算法包装基本的原价算法
cr7.decorate(cr6); //满200返50算法装饰打7折算法
this.cs = cr7; //将包装好的算法组合引用传递给cs对象
break;
}
}
public double getResult(double price,int num){
//根据收费策略的不同,获得计算结果
return this.cs.acceptCash(price,num);
}
}

第 7 章 代理模式

代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。

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
/**
* @author 顾梦
* @create 2023/4/27
* 代理模式——为别人做嫁衣
*/
public class ProxyPattern {
public static void main(String[] args) {
SchoolGirl girlLjj = new SchoolGirl();
girlLjj.setName("李娇娇");

Proxy boyDl = new Proxy(girlLjj);
boyDl.giveDolls();
boyDl.giveFlowers();
boyDl.giveChocolate();
}
}

interface IGiveGift{
void giveDolls();
void giveFlowers();
void giveChocolate();
}

// 被追求者类
class SchoolGirl{
private String name;

public String getName(){
return this.name;
}

public void setName(String name){
this.name = name;
}
}

// 追求者类
class Pursuit implements IGiveGift{

private SchoolGirl mm;
public Pursuit(SchoolGirl mm){
this.mm = mm;
}

@Override
public void giveDolls() {
System.out.println(this.mm.getName() + ",你好!送你洋娃娃。");
}

@Override
public void giveFlowers() {
System.out.println(this.mm.getName() + ",你好!送你鲜花。");
}

@Override
public void giveChocolate() {
System.out.println(this.mm.getName() + ",你好!送你巧克力。");
}
}

// 代理类
class Proxy implements IGiveGift{

private Pursuit gg; // 认识追求者

public Proxy(SchoolGirl mm){
this.gg = new Pursuit(mm);
}

@Override
public void giveDolls() {
this.gg.giveDolls();
}

@Override
public void giveFlowers() {
this.gg.giveFlowers();
}

@Override
public void giveChocolate() {
this.gg.giveChocolate();
}
}

代理模式应用

  • 远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
  • 虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
  • 安全代理,用来控制真实对象访问的权限。
  • 智能指引,是指当调用真实的对象时,代理处理另外一些事。

第 8 章 工厂方法模式

工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

工厂方法模式是简单工厂模式的进一步抽象和推广。

优点:

  • 对于复杂的参数构造对象,可以很好地对外层屏蔽代码的复杂性
  • 很好的解耦能力


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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package cn.jishuqin.chapter08;

import java.util.*;

public class FactoryMethod {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

System.out.println("请输入数字A: ");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/、pow、log): ");
String strOperate = sc.nextLine();
System.out.println("请输入数字B: ");
double numberB = Double.parseDouble(sc.nextLine());

Operation operate = OperationFactory.createOperate(strOperate);
double result = operate.getResult(numberA, numberB);

System.out.println("结果是: " + result);
}
}

abstract class Operation {
public abstract double getResult(double numberA, double numberB) ;
}

class Add extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}

class Sub extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}

class Mul extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return numberA * numberB;
}
}

class Div extends Operation {
@Override
public double getResult(double numberA, double numberB) {
if (numberB == 0) {
System.out.println("除数不能为0");
throw new ArithmeticException();
}
return numberA / numberB;
}
}

// 指数运算类,求numberA的numberB次方
class Pow extends Operation{

@Override
public double getResult(double numberA, double numberB) {
// 此处缺两参数的有效性检测
return Math.pow(numberA,numberB);
}
}

// 对数运算类,求以numberA为底的numberB的对数
class Log extends Operation{

@Override
public double getResult(double numberA, double numberB) {
// 此处缺两参数的有效性检测
return Math.log(numberB) / Math.log(numberA);
}
}

interface IFactory{
Operation createOperation(String operType);
}

// 基础运算工厂
class FactoryBasic implements IFactory{

@Override
public Operation createOperation(String operType) {
Operation oper = null;
switch (operType){
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}

// 高级运算工厂
class FactoryAdvanced implements IFactory{

@Override
public Operation createOperation(String operType) {
Operation oper = null;
switch (operType){
case "pow":
oper = new Pow(); // 指数运算类实例
break;
case "log":
oper = new Log(); // 对数运算类实例
break;
// 此处可扩展其他高级运算类的实例化,可修改
// 当前工厂类不会影响到基础运算工厂类

}
return oper;
}
}

class OperationFactory{
public static Operation createOperate(String operate){
Operation oper = null;
IFactory factory = null;
switch (operate){
case "+":
case "-":
case "*":
case "/":
// 基础运算工厂实例
factory = new FactoryBasic();
break;
case "pow":
case "log":
// 高级运算工厂实例
factory = new FactoryAdvanced();
}
// 利用多态返回实际的运算类实例
oper = factory.createOperation(operate);
return oper;
}
}

第 9 章 原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

浅复制与深复制:

  • 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 深复制:深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

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
package cn.jishuqin.chapter09;

/**
* @author 顾梦
* @create 2023/5/4
* 简历复印——原型模式
*/
public class PrototypePattern{
public static void main(String[] args) {
Resume resume1 = new Resume("大鸟");
resume1.setPersonalInfo("男","29");
resume1.setWorkExperience("1998-2000","xx公司");

Resume resume2 = resume1.clone();
resume2.setWorkExperience("2000-2003","YY集团");

Resume resume3 = resume1.clone();
resume3.setPersonalInfo("男","24");

resume1.display();
resume2.display();
resume3.display();
}
}

// 工作经历类
class WorkExperience implements Cloneable{
// 工作时间范围
private String timeArea;

public String getTimeArea() {
return timeArea;
}

public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}

// 所在公司
private String company;

public String getCompany() {
return company;
}

public void setCompany(String company) {
this.company = company;
}

public WorkExperience clone(){
WorkExperience object = null;
try{
object = (WorkExperience) super.clone();
}catch (CloneNotSupportedException exception){
System.out.println("Clone异常。");
}
return object;
}
}

// 简历类
class Resume implements Cloneable{
private String name;
private String sex;
private String age;
private WorkExperience work;
public Resume(String name) {
this.name = name;
this.work = new WorkExperience();
}

// 设置个人信息
public void setPersonalInfo(String sex,String age){
this.sex = sex;
this.age = age;
}

// 设置工作经历
public void setWorkExperience(String timeArea,String company){
this.work.setTimeArea(timeArea); // 给工作经历实例的时间范围赋值
this.work.setCompany(company); // 给工作经历实例的公司赋值
}

// 展示简历
public void display(){
System.out.println(this.name + " " + this.sex + " " + this.age);
System.out.println("工作经历 " + this.work.getTimeArea() + " " + this.work.getCompany());
}

@Override
protected Resume clone() {
Resume object = null;
try {
object = (Resume) super.clone();
object.work = this.work.clone(); // 深复制
}catch (CloneNotSupportedException exception){
System.out.println("Clone 异常。");
}
return object;
}
}

第 10 章 模板方法模式

模板方法(Template Method)模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

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
package cn.jishuqin.chapter10;

public class TemplateMethod {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClassA();
abstractClass.templateMethod();

abstractClass = new ConcreteClassB();
abstractClass.templateMethod();
}
}

// 模板方法抽象类
abstract class AbstractClass{
// 模板方法
public void templateMethod(){

// 写一些可以被子类共享的代码
System.out.println("共享的代码~");

this.primitiveOperation1();
this.primitiveOperation2();

}

public abstract void primitiveOperation1(); // 子类个性的行为,放到子类去实现
public abstract void primitiveOperation2(); // 子类个性的行为,放到子类去实现
}

// 模板方法具体类A
class ConcreteClassA extends AbstractClass{

@Override
public void primitiveOperation1() {
System.out.println("具体类A方法1实现");
}

@Override
public void primitiveOperation2() {
System.out.println("具体类A方法2实现");
}
}

// 模板方法具体类B
class ConcreteClassB extends AbstractClass{

@Override
public void primitiveOperation1() {
System.out.println("具体类B方法1实现");
}

@Override
public void primitiveOperation2() {
System.out.println("具体类B方法2实现");
}
}

模板方法模式的特点

  • 模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。
  • 模板方法模式就是提供了一个很好的代码复用平台。

第 11 章 迪米特法则

迪米特法则(LoD),也叫最少知识原则。
迪米特法则(LoD):如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

第 12 章 外观模式

外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

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
package cn.jishuqin.chapter11;

/**
* @author 顾梦
* @create 2023/5/5
* 外观模式
*/
public class FacadePattern {
public static void main(String[] args) {
Facade facade = new Facade();

facade.methodA();
facade.methodB();
}
}

// 子系统1
class SubSystemOne{
public void methodOne(){
System.out.println("子系统方法一");
}
}

// 子系统2
class SubSystemTwo{
public void methodTwo(){
System.out.println("子系统方法二");
}
}

// 子系统3
class SubSystemThree{
public void methodThree(){
System.out.println("子系统方法三");
}
}

// 子系统1
class SubSystemFour{
public void methodFour(){
System.out.println("子系统方法四");
}
}

// 外观类
// 它需要了解所有子系统的方法或属性,进行组合以被外界调用
class Facade{
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;

public Facade(){
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}

public void methodA(){
one.methodOne();
two.methodTwo();
three.methodThree();
four.methodFour();
}

public void methodB(){
two.methodTwo();
three.methodThree();
}
}

第 13 章 建造者模式

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

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
package cn.jishuqin.chapter13;

import java.util.*;

/**
* @author 顾梦
* @create 2023/5/5
* 建造者模式
*/
public class BuilderPattern {
public static void main(String[] args) {
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();

// 指挥者用ConcreteBuilder1的方法来建造产品
director.construct(b1); // 创建的是产品A和产品B
Product p1 = b1.getResult();
p1.show();

// 指挥者用ConcreteBuilder2的方法来建造产品
director.construct(b2); // 创建的是产品X和产品Y
Product p2 = b2.getResult();
p2.show();

}
}

// 产品类
class Product {
ArrayList<String> parts = new ArrayList<String>();

// 添加新的产品部件
public void add(String part){
parts.add(part);
}

// 列举所有产品部件
public void show(){
for (String part : parts) {
System.out.println(part);
}
}
}

// 抽象的建造者类
abstract class Builder {
public abstract void buildPartA(); // 建造部件A
public abstract void buildPartB(); // 建造部件B
public abstract Product getResult(); // 得到产品
}

// 具体建造者1
class ConcreteBuilder1 extends Builder {

private Product product = new Product();

@Override
public void buildPartA() {
product.add("部件A");
}

@Override
public void buildPartB() {
product.add("部件B");
}

@Override
public Product getResult() {
return product;
}
}

// 具体建造者2
class ConcreteBuilder2 extends Builder {

private Product product = new Product();

@Override
public void buildPartA() {
product.add("部件X");
}

@Override
public void buildPartB() {
product.add("部件Y");
}

@Override
public Product getResult() {
return product;
}
}

// 指挥者
class Director{
public void construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
}
}

建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。

第 14 章 观察者模式

观察者模式又叫作发布-订阅(Publish/Subscri)模式。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

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
package cn.jishuqin.chapter14;

import java.util.*;

/**
* @author 顾梦
* @create 2023/5/6
* 观察者模式
*/
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
subject.attach(new ConcreteObserver("NameX",subject));
subject.attach(new ConcreteObserver("NameY",subject));
subject.attach(new ConcreteObserver("NameZ", subject));
subject.setSubjectState("ABC");

subject.notifyObserver();
}
}

// 通知者抽象类
abstract class Subject {
private ArrayList<Observer> list = new ArrayList<Observer>(); // 针对抽象的Observer编程

// 增加观察者
public void attach(Observer observer){
list.add(observer);
}

// 减少观察者
public void detach(Observer observer){
list.remove(observer);
}

// 通知观察者
public void notifyObserver(){
for (Observer item : list) {
item.update();
}
}

protected String subjectState;
public String getSubjectState() {
return this.subjectState;
}
public void setSubjectState(String value) {
this.subjectState = value;
}
}

// 抽象观察者
abstract class Observer {
public abstract void update();
}

// 具体通知者
class ConcreteSubject extends Subject{
// 具体通知者的方法
}

// 具体观察者类
class ConcreteObserver extends Observer{
private String name;
private Subject sub;
public ConcreteObserver(String name,Subject sub){
this.name = name;
this.sub = sub;
}


@Override
public void update() {
System.out.println("观察者"+this.name+"的新状态是"+this.sub.getSubjectState());
}
}

特点:

  • 当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
  • 抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
  • 观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

第 15 章 抽象工厂模式

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package cn.jishuqin.chapter15;

/**
* @author 顾梦
* @create 2023/5/6
* 抽象工厂模式
*/
public class AbstractFactory {
public static void main(String[] args) {
User user = new User();
Department department = new Department();

IFactory factory = new SqlserverFactory();

IUser iu = factory.createUser();
iu.insert(user); // 新增一个用户
iu.getUser(1); //得到用户ID为1的用户信息

IDepartment idept = factory.createDepartment();
idept.insert(department);
idept.getDepartment(2);
}
}

// 用户类
class User{

// 用户ID
private int _id;
public int getId() {
return this._id;
}
public void setId(int value) {
this._id = value;
}

// 用户姓名
private String _name;
public String getName(){
return this._name;
}
public void setName(String value){
this._name = value;
}
}

// 部门类
class Department{

// 部门ID
private int _id;

public int get_id() {
return this._id;
}
public void set_id(int value){
this._id = value;
}

// 部门名称
private String _name;
public String getName() {
return this._name;
}
public void setName(String value){
this._name = value;
}
}

interface IUser{
void insert(User user);
User getUser(int id);
}

// 部门类接口
interface IDepartment{
void insert(Department department);
Department getDepartment(int id);
}

class SqlserverUser implements IUser{

// 新增一个用户
public void insert(User user){
System.out.println("在SQL Server中给User表增加一条记录");
}

// 获取一个用户信息
@Override
public User getUser(int id) {
System.out.println("在SQL Server中根据用户ID得到User表一条记录");
return null;
}
}

class AccessUser implements IUser{

// 新增一个用户
@Override
public void insert(User user) {
System.out.println("在Access中给User表增加一条记录");
}

@Override
public User getUser(int id) {
System.out.println("在Access中根据用户ID得到User表一条记录");
return null;
}
}

class SqlserverDepartment implements IDepartment{

// 新增一个部门
public void insert(Department department){
System.out.println("在SQLServer中给Department表增加一条记录");
}

@Override
public Department getDepartment(int id) {
System.out.println("在SQL Server中根据部门ID得到Department表一条记录");
return null;
}
}

class AccessDepartment implements IDepartment{

// 新增一个部门
public void insert(Department department){
System.out.println("在Access中给Department表增加一条记录");
}

@Override
public Department getDepartment(int id) {
System.out.println("在Access中根据部门ID得到Department表一条记录");
return null;
}
}

// 工厂接口
interface IFactory{
IUser createUser();
IDepartment createDepartment(); // 增加的接口方法
}

// Sqlserver工厂
class SqlserverFactory implements IFactory{

@Override
public IUser createUser() {
return new SqlserverUser();
}

@Override
public IDepartment createDepartment() {
return new SqlserverDepartment();
}
}

// Access工厂
class AccessFactory implements IFactory{

@Override
public IUser createUser() {
return new AccessUser();
}

@Override
public IDepartment createDepartment() {
return new AccessDepartment();
}
}

特点:

  • 易于交换产品系列,由于具体工厂类,在一应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
  • 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

第 16 章 状态模式

状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package cn.jishuqin.chapter16;

public class StatePattern {
public static void main(String[] args) {
// 紧急项目
Work emergencyProjects = new Work();
emergencyProjects.setHour(9);
emergencyProjects.writeProgram();
emergencyProjects.setHour(10);
emergencyProjects.writeProgram();
emergencyProjects.setHour(12);
emergencyProjects.writeProgram();
emergencyProjects.setHour(13);
emergencyProjects.writeProgram();
emergencyProjects.setHour(14);
emergencyProjects.writeProgram();
emergencyProjects.setHour(17);

emergencyProjects.setWorkFinished(false);

emergencyProjects.writeProgram();
emergencyProjects.setHour(19);
emergencyProjects.writeProgram();
emergencyProjects.setHour(22);
emergencyProjects.writeProgram();

}
}

// 工作类
class Work{

private State current;

public Work(){
current = new ForenoonState();
}
// 设置状态
public void setState(State value){
this.current =value;
}

// 写代码的状态
public void writeProgram(){
this.current.writeProgram(this);
}

// 时间终点
private int hour;
public int getHour() {
return this.hour;
}
public void setHour(int value) {
this.hour = value;
}
// 是否完成工作任务
private boolean workFinished = false;
public boolean getWorkFinished() {
return this.workFinished;
}

public void setWorkFinished(boolean value){
this.workFinished = value;
}
}

abstract class State {
public abstract void writeProgram(Work w);
}

// 上午工作状态
class ForenoonState extends State{
public void writeProgram (Work w){
if (w.getHour() < 12){
System.out.println("当前时间:" + w.getHour() + "点 上午工作,精神百倍");
}else {
w.setState(new NoonState());
w.writeProgram();
}
}
}

// 中午工作状态
class NoonState extends State{
public void writeProgram (Work w){
if (w.getHour() < 13){
System.out.println("当前时间:" + w.getHour() + "点 饿了,午饭:犯困,午休");
}else {
w.setState(new AfternoonState());
w.writeProgram();
}
}
}

// 下午工作状态
class AfternoonState extends State{
public void writeProgram (Work w){
if (w.getHour() < 17){
System.out.println("当前时间:" + w.getHour() + "点 下午状态还不错,继续努力");
}else {
w.setState(new EveningState());
w.writeProgram();
}
}
}

// 晚间工作状态
class EveningState extends State{
public void writeProgram (Work w){
if (w.getWorkFinished()){
w.setState(new RestState());
w.writeProgram();
}else {
if (w.getHour() < 21){
System.out.println("当前时间:" + w.getHour() + "点 加班哦,疲累之极");
}else {
w.setState(new SleepingState());
w.writeProgram();
}
}
}
}

// 睡眠状态
class SleepingState extends State{

@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 不行了,睡着了。");
}
}

// 下班休息状态
class RestState extends State{

@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 下班回家了。");
}
}

状态模式的好处与用处:

  • 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
  • 消除庞大的条件分支语句,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。
  • 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。

第 17 章 适配器模式

适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

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
package cn.jishuqin.chapter17;

public class AdapterPattern {
public static void main(String[] args) {
Player forwards = new Forwards("巴蒂尔");
forwards.attack();

Player guards = new Guards("麦克格雷迪");
guards.attack();

Player center = new Translator("姚明");

center.attack();
center.defense();
}
}

// 球员
abstract class Player{
protected String name;
public Player(String name){
this.name = name;
}

public abstract void attack(); // 进攻
public abstract void defense(); // 防守
}

// 前锋
class Forwards extends Player{
public Forwards(String name){
super(name);
}
public void attack() {
System.out.println("前锋 " + this.name + " 进攻");
}
public void defense(){
System.out.println("前锋 " + this.name + " 防守");
}
}

// 前锋
class Center extends Player{
public Center(String name){
super(name);
}
public void attack() {
System.out.println("中锋 " + this.name + " 进攻");
}
public void defense(){
System.out.println("中锋 " + this.name + " 防守");
}
}

// 后卫
class Guards extends Player{
public Guards(String name){
super(name);
}
public void attack() {
System.out.println("后卫 " + this.name + " 进攻");
}
public void defense(){
System.out.println("后卫 " + this.name + " 防守");
}
}

// 外籍中锋
class ForeignCenter{
private String name;
public String getName(){
return this.name;
}
public void setName(String value) {
this.name = value;
}
public void 进攻(){
System.out.println("外籍中锋 " +this.name + " 进攻");
}
public void 防守(){
System.out.println("外籍中锋 " +this.name + " 防守");
}
}

// 翻译者
class Translator extends Player{

private ForeignCenter foreignCenter = new ForeignCenter();

public Translator(String name){
super(name);
foreignCenter.setName(name);
}

@Override
public void attack() {
foreignCenter.进攻();
}

@Override
public void defense() {
foreignCenter.防守();
}
}

第 18 章 备忘录模式

备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

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
package cn.jishuqin.chapter18;

public class MementoPattern {
public static void main(String[] args) {
Originator o = new Originator();
o.setState("On");
o.show();

Caretaker c = new Caretaker();
// 保存状态时,由于有了很好的封装,可以隐藏Originator的实现细节
c.setMemento(o.createMemento());

// Originator改变了状态属性为"off"
o.setState("off");
o.show();

// 恢复原初始状态
o.recoveryMemento(c.getMemento());
o.show();
}
}

// 发起人
class Originator{

// 状态
private String state;
public String getState(){
return this.state;
}
public void setState(String value){
this.state = value;
}
// 显示数据
public void show(){
System.out.println("State:" + this.state);
}
// 创建备忘录
public Memento createMemento(){
return new Memento(this.state);
}
// 恢复备忘录
public void recoveryMemento(Memento memento){
this.setState(memento.getState());
}
}

// 备忘录
class Memento{
private String state;

public Memento(String state){
this.state = state;
}

public String getState(){
return this.state;
}
public void setState(String value){
this.state = value;
}
}

// 管理者
class Caretaker{
private Memento memento;
public Memento getMemento(){
return this.memento;
}
public void setMemento(Memento value){
this.memento = value;
}


}

第 19 章 组合模式

组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

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
package cn.jishuqin.chapter19;

import java.util.ArrayList;

public class CompositePattern {
public static void main(String[] args) {
Composite root = new Composite("root");
root.add(new Leaf("Leaf A"));
root.add(new Leaf("Leaf B"));

Composite comp = new Composite("Composite X");
comp.add(new Leaf("Leaf XA"));
comp.add(new Leaf("Leaf XB"));
root.add(comp);

Composite comp2 = new Composite("Composite XY");
comp2.add(new Leaf("Leaf XYA"));
comp2.add(new Leaf("Leaf XYB"));
comp.add(comp2);

Leaf leaf = new Leaf("Leaf C");
root.add(leaf);

Leaf leaf2 = new Leaf("Leaf D");
root.add(leaf2);
root.remove(leaf2);

root.display(1);

}
}

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

public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int depth);
}

class Leaf extends Component {

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

@Override
public void add(Component component) {
System.out.println("Cannot add to a leaf.");
}

@Override
public void remove(Component component) {
System.out.println("Cannot remove from a leaf.");
}

@Override
public void display(int depth) {
// 叶节点的具体显示方法,此处是显示其名称和级别
for (int i = 0; i < depth; i++)
System.out.print("-");
System.out.println(name);
}
}

class Composite extends Component{

private ArrayList<Component> children = new ArrayList<Component>(); // 一个子对象集合用来存储其下属的枝节点和叶节点

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

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

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

@Override
public void display(int depth) {
// 显示其枝节点名称
for (int i = 0;i<depth;i++)
System.out.print("-");
System.out.println(name);
// 对其下级进行遍历
for (Component item : children) {
item.display(depth+2);
}
}
}

需求中是体现部分与整体层次的结构时,希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式。

第 20 章 迭代器模式

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

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
package cn.jishuqin.chapter20;

import java.util.ArrayList;

public class IteratorPattern {
public static void main(String[] args) {
ConcreteAggregate bus = new ConcreteAggregate();
bus.add("大鸟");
bus.add("小菜");
bus.add("行李");
bus.add("老外");
bus.add("公交内部员工");
bus.add("小偷");

Iterator conductor = new ConcreteIterator(bus);

conductor.first();
while (!conductor.isDone()){
System.out.println(conductor.currentItem() + ",请买车票!");
conductor.next();
}
}
}

// 聚集抽象类
abstract class Aggregate{
// 创建迭代器
public abstract Iterator createIterator();
}

// 具体聚集类,继承Aggregate
class ConcreteAggregate extends Aggregate{

// 声明一个ArrayList泛型变量,用于存放聚合对象
private ArrayList<Object> items = new ArrayList<Object>();

@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}

// 返回聚焦总个数
public int getCount(){
return items.size();
}

// 增加新对象
public void add(Object object){
items.add(object);
}

// 得到指定索引对象
public Object getCurrentItem(int index){
return items.get(index);
}
}

// 迭代器抽象类
abstract class Iterator{
public abstract Object first(); // 第一个
public abstract Object next(); // 下一个
public abstract boolean isDone(); // 是否到最后
public abstract Object currentItem(); // 当前对象
}

// 具体迭代器类,继承Iterator
class ConcreteIterator extends Iterator{

private ConcreteAggregate aggregate;
private int current = 0;

// 初始化时将具体的聚焦对象传入
public ConcreteIterator(ConcreteAggregate aggregate){
this.aggregate = aggregate;
}

// 得到第一个对象
@Override
public Object first() {
return aggregate.getCurrentItem(0);
}

// 得到下一个对象
@Override
public Object next() {
Object ret = null;
current++;
if (current < aggregate.getCount()){
ret = aggregate.getCurrentItem(current);
}
return ret;
}

// 判断当前是否遍历到结尾,到结尾返回true
@Override
public boolean isDone() {
return current >= aggregate.getCount() ? true : false;
}

// 返回当前的聚集对象
@Override
public Object currentItem() {
return aggregate.getCurrentItem(current);
}
}

当你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。

迭代器(Iterator)模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。

第 21 章 单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

懒汉单例:要在第一次被引用时,才会将自己实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 单例模式(懒汉单例)
public class Singleton {
private static Singleton instance;

// 构造方法private化
private Singleton1(){

}

// 得到Singleton的实例(唯一途径)
public static Singleton getInstance() {
if (instance == null){
instance = new Singleton();
}
return instance;
}
}

饿汉单例:静态初始化的方式是在自己被加载时就将自己实例化

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

private static Singleton instance = new Singleton();

// 构造方法private化
private Singleton(){

}

// 得到Singleton的实例(唯一途径)
public static Singleton getInstance() {
return instance;
}
}

第 22 章 桥接模式

合成/聚合复用原则(CAPP),尽量使用合成/聚合,尽量不要使用类继承。

桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化。

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
package cn.jishuqin.chapter22;

public class BridgePattern {
public static void main(String[] args) {
Abstraction ab;
ab = new RefinedAbstraction();

ab.setImplementor(new ConcreteImplementorA());
ab.operation();

ab.setImplementor(new ConcreteImplementorB());
ab.operation();
}
}

abstract class Implementor{
public abstract void operation();
}

class ConcreteImplementorA extends Implementor{

@Override
public void operation() {
System.out.println("具体实现A的方法执行");
}
}

class ConcreteImplementorB extends Implementor{

@Override
public void operation() {
System.out.println("具体实现B的方法执行");
}
}

abstract class Abstraction{
protected Implementor implementor;

public void setImplementor(Implementor implementor){
this.implementor = implementor;
}

public abstract void operation();
}

class RefinedAbstraction extends Abstraction{

@Override
public void operation() {
System.out.println("具体的Abstraction");
implementor.operation();
}
}

实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。

第 23 章 命令模式

命令模式(Command),讲一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

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
107
108
109
110
package cn.jishuqin.chapter23;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class CommandPattern {
public static void main(String[] args) {
// 开店前的准备
Barbecuer boy = new Barbecuer(); // 烤肉厨师
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy); // 烤羊肉串
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy); // 烤羊肉串
Waiter girl = new Waiter(); // 服务员

System.out.println("开门营业,顾客点菜");
girl.setOrder(bakeMuttonCommand1); // 下单烤羊肉串
girl.setOrder(bakeMuttonCommand1); // 下单烤羊肉串
girl.setOrder(bakeMuttonCommand1); // 下单烤羊肉串
girl.setOrder(bakeMuttonCommand1); // 下单烤羊肉串
girl.setOrder(bakeMuttonCommand1); // 下单烤羊肉串

girl.cancelOrder(bakeMuttonCommand1); // 取消一串羊肉串订单

girl.setOrder(bakeChickenWingCommand1); // 下单烤鸡翅

System.out.println("点菜完毕,通知厨房烧菜");
girl.notifyCommand(); //通知厨师
}
}

// 烤肉串者
class Barbecuer{
// 烤羊肉
public void bakeMutton(){
System.out.println("烤羊肉串!");
}
// 烤鸡翅
public void bakeChickenWing(){
System.out.println("烤鸡翅!");
}
}

// 抽象命令类
abstract class Command{
protected Barbecuer receiver;

public Command(Barbecuer receiver){
this.receiver = receiver;
}
// 执行命令
public abstract void excuteCommand();
}

// 烤羊肉命令类
class BakeMuttonCommand extends Command {
public BakeMuttonCommand(Barbecuer receiver){
super(receiver);
}

@Override
public void excuteCommand() {
receiver.bakeMutton();
}
}

// 烤鸡翅命令类
class BakeChickenWingCommand extends Command{
public BakeChickenWingCommand(Barbecuer receiver){
super(receiver);
}

@Override
public void excuteCommand() {
receiver.bakeChickenWing();
}
}

// 服务员类
class Waiter{
private ArrayList<Command> orders = new ArrayList<Command>();

// 设置订单
public void setOrder(Command command){
String className= command.getClass().getSimpleName();

if (className.equals("BakeChickenWingCommand")){
System.out.println("服务员:鸡翅没有了,请点别的烧烤。");
}else {
this.orders.add(command);
System.out.println("增加订单:"+className + "时间:"+getNowTime());
}
}
// 取消订单
public void cancelOrder(Command command){
String className = command.getClass().getSimpleName();
orders.remove(command);
System.out.println("取消订单:"+className+" 时间:" + getNowTime());
}
// 通知执行
public void notifyCommand(){
for (Command command : orders) {
command.excuteCommand();
}
}

private String getNowTime(){
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
return formatter.format(new Date()).toString();
}
}

优点:

  • 能较容易地设计一个命令队列
  • 在需要的情况下,可以较容易地将命令记入日志
  • 允许接收请求的一方决定是否要否决请求
  • 可以容易地实现对请求的撤销和重做
  • 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易
  • 命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开

第 24 章 职责链模式

职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

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
package cn.jishuqin.chapter24;

public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
h1.setSuccessor(h2);
h2.setSuccessor(h3);

int[] requests = {2,5,14,22,18,3,27,20};

for (int request : requests) {
h1.handleRequest(request);
}
}
}

abstract class Handler{
protected Handler successor;

// 设置继任者
public void setSuccessor(Handler successor) {
this.successor = successor;
}

public abstract void handleRequest(int request);
}

class ConcreteHandler1 extends Handler {

@Override
public void handleRequest(int request) {
if (request >= 0 && request < 10){
System.out.println(this.getClass().getSimpleName() + " 处理请求 "+request);
}else if(successor != null){
successor.handleRequest(request);
}
}
}

class ConcreteHandler2 extends Handler {

@Override
public void handleRequest(int request) {
if (request >= 10 && request < 20){
System.out.println(this.getClass().getSimpleName() + " 处理请求 "+request);
}else if(successor != null){
successor.handleRequest(request);
}
}
}


class ConcreteHandler3 extends Handler {

@Override
public void handleRequest(int request) {
if (request >= 20 && request < 30){
System.out.println(this.getClass().getSimpleName() + " 处理请求 "+request);
}else if(successor != null){
successor.handleRequest(request);
}
}
}

职责链的好处:

  • 接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接收者的引用。
  • 可以随时地增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性。

第 25 章 中介者模式

中介者模式(Mediator),用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

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
package cn.jishuqin.chapter25;

public class MediatorPattern {
public static void main(String[] args) {
ConcreteMediator m = new ConcreteMediator();

ConcreteColleague1 c1 = new ConcreteColleague1(m);
ConcreteColleague2 c2 = new ConcreteColleague2(m);

m.setColleague1(c1);
m.setColleague2(c2);

c1.send("吃过饭了吗?");
c2.send("没有呢,你打算请客?");
}
}

abstract class Colleague{
protected Mediator mediator;
// 构造方法,得到中介者对象
public Colleague(Mediator mediator){
this.mediator = mediator;
}
}

class ConcreteColleague1 extends Colleague{
public ConcreteColleague1(Mediator mediator){
super(mediator);
}

public void send(String message) {
this.mediator.send(message,this);
}

public void notify(String message) {
System.out.println("同事1得到信息:"+message);
}
}

class ConcreteColleague2 extends Colleague{
public ConcreteColleague2(Mediator mediator){
super(mediator);
}

public void send(String message) {
this.mediator.send(message,this);
}

public void notify(String message) {
System.out.println("同事2得到信息:"+message);
}
}

// 中介者类
abstract class Mediator{
// 定义一个抽象的发送消息方法,得到同事对象和发送消息
public abstract void send(String message,Colleague colleague);
}

class ConcreteMediator extends Mediator {

private ConcreteColleague1 colleague1;
private ConcreteColleague2 colleague2;

public void setColleague1(ConcreteColleague1 value){
this.colleague1 = value;
}

public void setColleague2(ConcreteColleague2 value){
this.colleague2 = value;
}

@Override
public void send(String message, Colleague colleague) {
if (colleague == colleague1){
colleague2.notify(message);
}else {
colleague1.notify(message);
}
}
}

中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。

第 26 章 享元模式

享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。

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
package cn.jishuqin.chapter26;

import java.util.Hashtable;

public class FlyweightPattern {
public static void main(String[] args) {
int extrinsicstate = 22;

FlyweightFactory f = new FlyweightFactory();

Flyweight fx = f.getFlyweight("X");
fx.operation(--extrinsicstate);

Flyweight fy = f.getFlyweight("Y");
fy.operation(--extrinsicstate);

Flyweight fz = f.getFlyweight("Z");
fz.operation(--extrinsicstate);

Flyweight uf = new UnsharedConcreteFlyweight();

uf.operation(--extrinsicstate);
}
}

abstract class Flyweight{
public abstract void operation(int extrinsicstate);
}

// 需要共享的具体Flyweight子类
class ConcreteFlyweight extends Flyweight{
@Override
public void operation(int extrinsicstate) {
System.out.println("具体Flyweight:" + extrinsicstate);
}
}

// 不需要共享的Flyweight子类
class UnsharedConcreteFlyweight extends Flyweight{

@Override
public void operation(int extrinsicstate) {
System.out.println("不共享的具体Flyweight:" + extrinsicstate);
}
}

// 享元工厂
class FlyweightFactory{
private Hashtable<String,Flyweight> flyweights = new Hashtable<String,Flyweight>();

public FlyweightFactory(){
flyweights.put("X",new ConcreteFlyweight());
flyweights.put("Y",new ConcreteFlyweight());
flyweights.put("Z",new ConcreteFlyweight());
}

public Flyweight getFlyweight(String key){
return flyweights.get(key);
}
}

如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用享元模式;还有就是对象的大多数状态可以是外部状态,如果删除对象的外部状态,那么可以相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

第 27 章 解释器模式

解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

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
package cn.jishuqin.chapter27;

import java.util.ArrayList;

public class InterpreterPattern {
public static void main(String[] args) {
Context context = new Context();
ArrayList<AbstractExpression> list = new ArrayList<AbstractExpression>();
list.add(new TerminalExpression());
list.add(new NonterminalExpression());
list.add(new TerminalExpression());
list.add(new TerminalExpression());

for (AbstractExpression exp : list) {
exp.interpret(context);
}
}
}

// 抽象表达式
abstract class AbstractExpression{
// 解释操作
public abstract void interpret(Context context);
}

// 终结符表达式
class TerminalExpression extends AbstractExpression{

@Override
public void interpret(Context context) {
System.out.println("终端解释器");
}
}

// 非终结符表达式
class NonterminalExpression extends AbstractExpression{

@Override
public void interpret(Context context) {
System.out.println("非终端解释器");
}
}

class Context{
private String input;
public String getInput() {
return this.input;
}
public void setInput(String value){
this.input = value;
}

private String output;
public String getOutput() {
return this.output;
}
public void setOutput(String value){
this.output = value;
}
}

如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。

这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

第 28 章 访问者模式

访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

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
package cn.jishuqin.chapter28;

import java.util.ArrayList;

public class VisitorPattern {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
o.attach(new ConcreteElementA());
o.attach(new ConcreteElementB());

ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor2 v2 = new ConcreteVisitor2();

o.accept(v1);
o.accept(v2);
}
}

abstract class Visitor {
public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);
}

class ConcreteVisitor1 extends Visitor {

@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+"被"+this.getClass().getSimpleName()+"访问");
}

@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+"被"+this.getClass().getSimpleName()+"访问");
}
}

class ConcreteVisitor2 extends Visitor {

@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+"被"+this.getClass().getSimpleName()+"访问");
}

@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+"被"+this.getClass().getSimpleName()+"访问");
}
}

abstract class Element{
public abstract void accept(Visitor visitor);
}

class ConcreteElementA extends Element{

@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}

public void operationA(){
// 其他相关操作
}
}

class ConcreteElementB extends Element{

@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}

public void operationA(){
// 其他相关操作
}
}

class ObjectStructure{
private ArrayList<Element> elements = new ArrayList<Element>();

public void attach(Element element){
elements.add(element);
}

public void detach(Element element){
elements.remove(element);
}

public void accept(Visitor visitor){
for (Element element : elements) {
element.accept(visitor);
}
}
}

访问者模式的目的是要把处理从数据结构分离出来,有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。

访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。

访问者模式将有关的行为集中到一个访问者对象中。


“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭ ”

微信二维码

微信支付

支付宝二维码

支付宝支付

大话设计模式
https://blog.jishuqin.cn/posts/4a5b6c7d/
作者
顾梦
发布于
2023年5月20日
更新于
2024年5月19日
许可协议