JAVA 设计模式

创建型模式

简单工厂模式

简单工厂模式⼜称⼯⼚⽅法模式,是⼀种创建型设计模式,在工厂类中提供⼀个创建对象的⽅法, 允许客户端决定实例化对象的类型。

定义接口

以文件转换为示例。

1
2
3
4
5
6
7
import java.io.File;

public interface Converter {

byte[] convertToPdf(File file) throws Exception;
byte[] convertToPdf(byte[] file) throws Exception;
}

实现文件转换接口

1. word转pdf
2. excel转pdf
3. ppt转pdf
4. 图片转pdf

文件转换工厂

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
public class ConvertPdfFactory {

private static String DOC = "doc";
private static String DOCX = "docx";
private static String JPG = "jpg";
private static String TIF = "tif";
private static String JPEG = "jpeg";
private static String XLS = "xls";
private static String XLSX= "xlsx";
private static String PPT= "ppt";
private static String PPTX= "pptx";

public static Converter create(String type){
if (type.toLowerCase().equals(DOC) || type.toLowerCase().equals(DOCX)){
return WordToPdf.create();
}
if (type.toLowerCase().equals(XLS) || type.toLowerCase().equals(XLSX)){
return ExcelToPdf.create();
}
if (type.toLowerCase().equals(PPT) || type.toLowerCase().equals(PPTX)){
return SlideToPdf.create();
}
if (type.toLowerCase().equals(JPG) || type.toLowerCase().equals(TIF) || type.toLowerCase().equals(JPEG)){
return ImageToPdf.create();
}
throw new NullPointerException("找不到转化类");
}
}

抽象工厂模式

抽象工厂是一个中心工厂,创建其他工厂的模式。

定义接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 工厂接口
public interface Factory<T> {
T produce();
}
//汽车接口
public interface Car {
String getName();
}
public class WulingCar implements Car{
@Override
public String getName() {
return "五菱汽车";
}
}
//飞机接口
public interface Plane {
String getName();
}
public class BoeingPlane implements Plane{
@Override
public String getName() {
return "波音飞机";
}
}

代码实现

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

// 汽车工厂
public class CarFactory implements Factory<Car>{
@Override
public Car produce() {
return new WulingCar();
}
}
// 飞机工厂
public class PlaneFactory implements Factory<Plane>{
@Override
public Plane produce() {
return new BoeingPlane();
}
}

public static void main(String[] args) {
Factory<Car> carFactory = new CarFactory();
Car car = carFactory.produce();
System.out.println(car.getName());

Factory<Plane> planeFactory = new PlaneFactory();
Plane plane = planeFactory.produce();
System.out.println(plane.getName());
}
1
2
五菱汽车
波音飞机

100%宽度

建造者模式

建造者模式所完成的内容就是通过将多个简单对象通过一步步的组装构建出一个复杂对象的过程。

代码实现

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
public class Phone {

private String name;
private String color;
private String size;
private String price;
private String ram;

public Phone(String name, String color, String size, String price, String ram) {
this.name = name;
this.color = color;
this.size = size;
this.price = price;
this.ram = ram;
}

public static class Builder{
private String name;
private String color;
private String size;
private String price;
private String ram;

public Builder(){}

public Builder name(String name){
this.name = name;
return this;
}
public Builder color(String color){
this.color = color;
return this;
}
public Builder size(String size){
this.size = size;
return this;
}
public Builder price(String price){
this.price = price;
return this;
}
public Builder ram(String ram){
this.ram = ram;
return this;
}

public Phone build(){
return new Phone(name,color,size,price,ram);
}
}

@Override
public String toString() {
return "Phone{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", size='" + size + '\'' +
", price='" + price + '\'' +
", ram='" + ram + '\'' +
'}';
}
}

原型模式

原型模式主要解决的问题就是创建重复对象,因此采用克隆的方式节省时间。

代码实现

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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
public class AnswerQuestion {
private String name; // 问题
private String key; // 答案

public AnswerQuestion(String name, String key) {
this.name = name;
this.key = key;
}

public String getName() {
return name;
}

public String getKey() {
return key;
}
}

public class ChoiceQuestion {
private String name; // 题目
private Map<String, String> option; // 选项;A、B、C、D
private String key; // 答案;B

public ChoiceQuestion(String name, Map<String, String> option, String key) {
this.name = name;
this.option = option;
this.key = key;
}

public String getName() {
return name;
}

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

public Map<String, String> getOption() {
return option;
}

public void setOption(Map<String, String> option) {
this.option = option;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}
}
public class QuestionBank implements Cloneable {

private String candidate; // 考生
private String number; // 考号

private ArrayList<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>();
private ArrayList<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>();

public QuestionBank append(ChoiceQuestion choiceQuestion) {
choiceQuestionList.add(choiceQuestion);
return this;
}

public QuestionBank append(AnswerQuestion answerQuestion) {
answerQuestionList.add(answerQuestion);
return this;
}

@Override
public Object clone() throws CloneNotSupportedException {
QuestionBank questionBank = (QuestionBank) super.clone();
questionBank.choiceQuestionList = (ArrayList<ChoiceQuestion>) choiceQuestionList.clone();
questionBank.answerQuestionList = (ArrayList<AnswerQuestion>) answerQuestionList.clone();

// 题目乱序
Collections.shuffle(questionBank.choiceQuestionList);
Collections.shuffle(questionBank.answerQuestionList);
// 答案乱序
ArrayList<ChoiceQuestion> choiceQuestionList = questionBank.choiceQuestionList;
for (ChoiceQuestion question : choiceQuestionList) {
Topic random = random(question.getOption(), question.getKey());
question.setOption(random.getOption());
question.setKey(random.getKey());
}
return questionBank;
}

public void setCandidate(String candidate) {
this.candidate = candidate;
}

public void setNumber(String number) {
this.number = number;
}

@Override
public String toString() {

StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" +
"考号:" + number + "\r\n" +
"--------------------------------------------\r\n" +
"一、选择题" + "\r\n\n");

for (int idx = 0; idx < choiceQuestionList.size(); idx++) {
detail.append("第").append(idx + 1).append("题:").append(choiceQuestionList.get(idx).getName()).append("\r\n");
Map<String, String> option = choiceQuestionList.get(idx).getOption();
for (String key : option.keySet()) {
detail.append(key).append(":").append(option.get(key)).append("\r\n");;
}
detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n");
}

detail.append("二、问答题" + "\r\n\n");

for (int idx = 0; idx < answerQuestionList.size(); idx++) {
detail.append("第").append(idx + 1).append("题:").append(answerQuestionList.get(idx).getName()).append("\r\n");
detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n");
}

return detail.toString();
}


/**
* 乱序Map元素,记录对应答案key
* @param option 题目
* @param key 答案
* @return Topic 乱序后 {A=c., B=d., C=a., D=b.}
*/
public Topic random(Map<String, String> option, String key) {
Set<String> keySet = option.keySet();
ArrayList<String> keyList = new ArrayList<String>(keySet);
Collections.shuffle(keyList);
HashMap<String, String> optionNew = new HashMap<String, String>();
int idx = 0;
String keyNew = "";
for (String next : keySet) {
String randomKey = keyList.get(idx++);
if (key.equals(next)) {
keyNew = randomKey;
}
optionNew.put(randomKey, option.get(next));
}
return new Topic(optionNew, keyNew);
}

public class Topic{
private Map<String, String> option;
private String key;

public Topic(Map<String, String> option, String key) {
this.option = option;
this.key = key;
}

public Map<String, String> getOption() {
return option;
}

public String getKey() {
return key;
}
}

}
public class QuestionBankController {
private QuestionBank questionBank = new QuestionBank();

public QuestionBankController() {

Map<String, String> map01 = new HashMap<String, String>();
map01.put("A", "JAVA2 EE");
map01.put("B", "JAVA2 Card");
map01.put("C", "JAVA2 ME");
map01.put("D", "JAVA2 HE");
map01.put("E", "JAVA2 SE");

Map<String, String> map02 = new HashMap<String, String>();
map02.put("A", "JAVA程序的main方法必须写在类里面");
map02.put("B", "JAVA程序中可以有多个main方法");
map02.put("C", "JAVA程序中类名必须与文件名一样");
map02.put("D", "JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来");

Map<String, String> map03 = new HashMap<String, String>();
map03.put("A", "变量由字母、下划线、数字、$符号随意组成;");
map03.put("B", "变量不能以数字作为开头;");
map03.put("C", "A和a在java中是同一个变量;");
map03.put("D", "不同类型的变量,可以起相同的名字;");

Map<String, String> map04 = new HashMap<String, String>();
map04.put("A", "STRING");
map04.put("B", "x3x;");
map04.put("C", "void");
map04.put("D", "de$f");

Map<String, String> map05 = new HashMap<String, String>();
map05.put("A", "31");
map05.put("B", "0");
map05.put("C", "1");
map05.put("D", "2");

questionBank.append(new ChoiceQuestion("JAVA所定义的版本中不包括", map01, "D"))
.append(new ChoiceQuestion("下列说法正确的是", map02, "A"))
.append(new ChoiceQuestion("变量命名规范说法正确的是", map03, "B"))
.append(new ChoiceQuestion("以下()不是合法的标识符",map04, "C"))
.append(new ChoiceQuestion("表达式(11+3*8)/4%3的值是", map05, "D"))
.append(new AnswerQuestion("小红马和小黑马生的小马几条腿", "4条腿"))
.append(new AnswerQuestion("铁棒打头疼还是木棒打头疼", "头最疼"))
.append(new AnswerQuestion("什么床不能睡觉", "牙床"))
.append(new AnswerQuestion("为什么好马不吃回头草", "后面的草没了"));
}

public String createPaper(String candidate, String number) throws CloneNotSupportedException {
QuestionBank questionBankClone = (QuestionBank) questionBank.clone();
questionBankClone.setCandidate(candidate);
questionBankClone.setNumber(number);
return questionBankClone.toString();
}

}

1
2
3
4
5
6
public static void main(String[] args) throws CloneNotSupportedException {
QuestionBankController questionBankController = new QuestionBankController();
System.out.println(questionBankController.createPaper("张三", "10001"));
System.out.println(questionBankController.createPaper("李四", "10002"));
System.out.println(questionBankController.createPaper("王五", "10003"));
}
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
考生:张三
考号:10001
--------------------------------------------
一、选择题

1题:下列说法正确的是
A:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
B:JAVA程序中类名必须与文件名一样
C:JAVA程序中可以有多个main方法
D:JAVA程序的main方法必须写在类里面
答案:D

2题:变量命名规范说法正确的是
A:变量不能以数字作为开头;
B:不同类型的变量,可以起相同的名字;
C:A和a在java中是同一个变量;
D:变量由字母、下划线、数字、$符号随意组成;
答案:A

3题:以下()不是合法的标识符
A:x3x;
B:de$f
C:STRING
D:void
答案:D

4题:表达式(11+3*8)/4%3的值是
A:0
B:2
C:31
D:1
答案:B

5题:JAVA所定义的版本中不包括
A:JAVA2 HE
B:JAVA2 EE
C:JAVA2 Card
D:JAVA2 ME
E:JAVA2 SE
答案:A

二、问答题

1题:铁棒打头疼还是木棒打头疼
答案:头最疼

2题:小红马和小黑马生的小马几条腿
答案:4条腿

3题:什么床不能睡觉
答案:牙床

4题:为什么好马不吃回头草
答案:后面的草没了


考生:李四
考号:10002
--------------------------------------------
一、选择题

1题:以下()不是合法的标识符
A:de$f
B:STRING
C:x3x;
D:void
答案:D

2题:JAVA所定义的版本中不包括
A:JAVA2 HE
B:JAVA2 EE
C:JAVA2 ME
D:JAVA2 SE
E:JAVA2 Card
答案:A

3题:变量命名规范说法正确的是
A:不同类型的变量,可以起相同的名字;
B:变量由字母、下划线、数字、$符号随意组成;
C:变量不能以数字作为开头;
D:A和a在java中是同一个变量;
答案:C

4题:表达式(11+3*8)/4%3的值是
A:2
B:0
C:1
D:31
答案:A

第5题:下列说法正确的是
A:JAVA程序中可以有多个main方法
B:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
C:JAVA程序的main方法必须写在类里面
D:JAVA程序中类名必须与文件名一样
答案:C

二、问答题

第1题:小红马和小黑马生的小马几条腿
答案:4条腿

第2题:什么床不能睡觉
答案:牙床

第3题:铁棒打头疼还是木棒打头疼
答案:头最疼

第4题:为什么好马不吃回头草
答案:后面的草没了


考生:王五
考号:10003
--------------------------------------------
一、选择题

第1题:变量命名规范说法正确的是
A:变量不能以数字作为开头;
B:不同类型的变量,可以起相同的名字;
C:A和a在java中是同一个变量;
D:变量由字母、下划线、数字、$符号随意组成;
答案:A

第2题:下列说法正确的是
A:JAVA程序中类名必须与文件名一样
B:JAVA程序的main方法必须写在类里面
C:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
D:JAVA程序中可以有多个main方法
答案:B

第3题:表达式(11+3*8)/4%3的值是
A:2
B:1
C:0
D:31
答案:A

4题:JAVA所定义的版本中不包括
A:JAVA2 SE
B:JAVA2 EE
C:JAVA2 HE
D:JAVA2 Card
E:JAVA2 ME
答案:C

5题:以下()不是合法的标识符
A:void
B:de$f
C:STRING
D:x3x;
答案:A

二、问答题

1题:什么床不能睡觉
答案:牙床

2题:铁棒打头疼还是木棒打头疼
答案:头最疼

3题:为什么好马不吃回头草
答案:后面的草没了

4题:小红马和小黑马生的小马几条腿
答案:4条腿

单例模式

单例模式的实现方式比较多,主要在实现上是否支持懒汉模式、是否线程安全中运用各项技巧。当然也有一些场景不需要考虑懒加载也就是懒汉模式的情况,会直接使用static静态类或属性和方法的方式进行处理,供外部调用。

静态类使用

1
2
3
4
5
public class Singleton {
public static Singleton singleton = new Singleton();

private Singleton(){}
}

懒汉模式

线程不安全

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
public static Singleton singleton = null;

private Singleton(){}

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

线程安全

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
public static Singleton singleton = null;

private Singleton(){}

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

使用内部类

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

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

双重锁校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton {
public static Singleton singleton = null;

private Singleton(){}

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

CAS「AtomicReference」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

private Singleton(){}

public static synchronized Singleton getInstance(){
for (; ; ) {
Singleton instance = INSTANCE.get();
if (null != instance) return instance;
INSTANCE.compareAndSet(null, new Singleton());
return INSTANCE.get();
}
}
}

枚举单例

1
2
3
4
5
6
public enum Singleton {
INSTANCE;
public void test(){
System.out.println("hi~");
}
}