Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6b824ac

Browse files
优惠券设计
1 parent cc06b11 commit 6b824ac

File tree

10 files changed

+2582
-71
lines changed

10 files changed

+2582
-71
lines changed
Lines changed: 292 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,320 @@
11
# 建造者模式
22

3-
建造者模式:封装一个对象的构造过程,并允许按步骤构造。建造者模式可以将一个类的构建和表示进行分离
3+
Builder 模式中文叫作建造者模式,又叫生成器模式,它属于对象创建型模式,是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节
44

5-
### 适用场景:
5+
在建造者模式中,有如下4种角色:
66

7-
- 隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
8-
- 多个部件都可以装配到一个对象中,但产生的运行结果不相同
9-
- 产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
10-
- 初始化一个对象时,参数过多,或者很多参数具有默认值
11-
- Builder模式不适合创建差异性很大的产品类
12-
产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
13-
- 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
7+
- Product:产品角色
8+
- Builder:抽象建造者,定义产品接口
9+
- ConcreteBuilder:具体建造者,实现Builder定义的接口,并且返回组装好的产品
10+
- Director:指挥者,属于这里面的老大,你需要生产什么产品都直接找它。
1411

15-
### 主要作用
12+
##建造者模式应用举例
1613

17-
- 用户只需要给出指定复杂对象的类型和内容;
18-
- 建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
14+
### 家装
1915

20-
### 两种形式
16+
家装不管是精装还是简装,它的流程都相对固定,所以它适用于建造者模式。我们就以家装为例,一起来学习了解一下建造者模式。下图是家装建造者模式简单的 UML 图。
2117

22-
建造者有两种形式:传统建造者模式和传统建造者模式变种。
18+
### 1、家装对象类
2319

24-
传统建造者模式:
20+
```java
21+
/**
22+
* 家装对象类
23+
*/
24+
public class House {
25+
// 买家电
26+
private String jiadian;
27+
28+
// 买地板
29+
private String diban;
30+
// 买油漆
31+
private String youqi;
32+
33+
public String getJiadian() {
34+
return jiadian;
35+
}
36+
37+
public void setJiadian(String jiadian) {
38+
this.jiadian = jiadian;
39+
}
40+
41+
public String getDiban() {
42+
return diban;
43+
}
44+
45+
public void setDiban(String diban) {
46+
this.diban = diban;
47+
}
48+
49+
public String getYouqi() {
50+
return youqi;
51+
}
52+
53+
public void setYouqi(String youqi) {
54+
this.youqi = youqi;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return "House{" +
60+
"jiadian='" + jiadian + '\'' +
61+
", diban='" + diban + '\'' +
62+
", youqi='" + youqi + '\'' +
63+
'}';
64+
}
65+
}
66+
```
67+
68+
### 2、抽象建造者 Builder 类
2569

2670
```java
27-
public class Computer {
28-
private final String cpu;//必须
29-
private final String ram;//必须
30-
private final int usbCount;//可选
31-
private final String keyboard;//可选
32-
private final String display;//可选
33-
34-
private Computer(Builder builder){
35-
this.cpu=builder.cpu;
36-
this.ram=builder.ram;
37-
this.usbCount=builder.usbCount;
38-
this.keyboard=builder.keyboard;
39-
this.display=builder.display;
71+
/**
72+
* 抽象建造者
73+
*/
74+
public interface HouseBuilder {
75+
// 买家电
76+
void doJiadian();
77+
// 买地板
78+
void doDiBan();
79+
// 买油漆
80+
void doYouqi();
81+
82+
House getHouse();
83+
}
84+
```
85+
86+
### 3、具体建造者-简装建造者类
87+
88+
```java
89+
/**
90+
* 简装创建者
91+
*/
92+
public class JianzhuangBuilder implements HouseBuilder {
93+
94+
private House house = new House();
95+
96+
@Override
97+
public void doJiadian() {
98+
house.setJiadian("简单家电就好");
4099
}
41-
public static class Builder{
42-
private String cpu;//必须
43-
private String ram;//必须
44-
private int usbCount;//可选
45-
private String keyboard;//可选
46-
private String display;//可选
47-
48-
public Builder(String cup,String ram){
49-
this.cpu=cup;
50-
this.ram=ram;
51-
}
52-
public Builder setDisplay(String display) {
53-
this.display = display;
54-
return this;
55-
}
56-
//set...
57-
public Computer build(){
58-
return new Computer(this);
59-
}
100+
101+
@Override
102+
public void doDiBan() {
103+
house.setDiban("普通地板");
104+
}
105+
106+
@Override
107+
public void doYouqi() {
108+
house.setYouqi("污染较小的油漆就行");
109+
}
110+
111+
@Override
112+
public House getHouse() {
113+
return house;
60114
}
61115
}
116+
```
117+
118+
### 4、具体建造者-精装建造者类
119+
120+
```text
121+
/**
122+
* 精装创建者
123+
*/
124+
public class jingzhuangBuilder implements HouseBuilder {
125+
126+
private House house = new House();
127+
128+
@Override
129+
public void doJiadian() {
130+
house.setJiadian("二话不说,最好的");
131+
}
132+
133+
@Override
134+
public void doDiBan() {
135+
house.setDiban("二话不说,实木地板");
136+
}
62137
63-
public class ComputerDirector {
64-
public void makeComputer(ComputerBuilder builder){
65-
builder.setUsbCount();
66-
builder.setDisplay();
67-
builder.setKeyboard();
138+
@Override
139+
public void doYouqi() {
140+
house.setYouqi("二话不说,给我来0污染的");
141+
}
142+
143+
@Override
144+
public House getHouse() {
145+
return house;
68146
}
69147
}
70148
```
71149

72-
传统建造者模式变种,链式调用:
150+
### 5、指挥官-家装公司类
73151

74152
```java
75-
public class LenovoComputerBuilder extends ComputerBuilder {
76-
private Computer computer;
77-
public LenovoComputerBuilder(String cpu, String ram) {
78-
computer=new Computer(cpu,ram);
153+
/**
154+
* 家装公司,值需要告诉他精装还是简装
155+
*/
156+
public class HouseDirector {
157+
158+
public House builder(HouseBuilder houseBuilder){
159+
houseBuilder.doDiBan();
160+
houseBuilder.doJiadian();
161+
houseBuilder.doYouqi();
162+
return houseBuilder.getHouse();
79163
}
80-
@Override
81-
public void setUsbCount() {
82-
computer.setUsbCount(4);
164+
}
165+
```
166+
167+
### 6、测试
168+
169+
```java
170+
public class App {
171+
public static void main(String[] args) {
172+
house();
173+
}
174+
175+
public static void house(){
176+
HouseDirector houseDirector = new HouseDirector();
177+
// 简装
178+
JianzhuangBuilder jianzhuangBuilder = new JianzhuangBuilder();
179+
System.out.println("我要简装");
180+
System.out.println(houseDirector.builder(jianzhuangBuilder));
181+
182+
// 精装
183+
jingzhuangBuilder jingzhuangBuilder = new jingzhuangBuilder();
184+
System.out.println("我要精装");
185+
System.out.println(houseDirector.builder(jingzhuangBuilder));
186+
187+
}
188+
}
189+
```
190+
191+
输出结果
192+
193+
```java
194+
我要简装
195+
House{jiadian="简单家电就好",diban='普通地板 ,youqi= 污染较小的油漆就行'
196+
我要精装
197+
House{jiadian='二话不说,最好的',diban='二话不说,实木地板,yougi='二话不说,给我来0污染的'}
198+
```
199+
200+
我们以家装为例,实现了两个具体的建造者,一个简装建造者、一个精装建造者。我们只需要告诉家装公司,我是需要简装还是精装,他会去帮我们安排,我不需要知道里面具体的细节。
201+
202+
### 对象构建
203+
204+
在日常开发中,你是不是会经常看到下面这种代码:
205+
206+
```java
207+
return new Docket(DocumentationType.SWAGGER_2)
208+
.apiInfo(apiInfo())
209+
.select()
210+
.apis(RequestHandlerSelectors.basePackage("com.curry.springbootswagger.controller"))
211+
.paths(PathSelectors.any())
212+
.build();
213+
```
214+
215+
是不是很优美?学会了 Builder 模式之后,你也可以通过这种方式进行对象构建。它是通过变种的 Builder 模式实现的。先不解释了,我们先用 Builder 模式来实现跟上述的对象构建,使用学生类为例。
216+
217+
学生对象代码:
218+
219+
```java
220+
public class Student {
221+
222+
private String name;
223+
224+
private int age;
225+
226+
private int num;
227+
228+
private String email;
229+
230+
// 提供一个静态builder方法
231+
public static Student.Builder builder() {
232+
return new Student.Builder();
233+
}
234+
// 外部调用builder类的属性接口进行设值。
235+
public static class Builder{
236+
private String name;
237+
238+
private int age;
239+
240+
private int num;
241+
242+
private String email;
243+
244+
public Builder name(String name) {
245+
this.name = name;
246+
return this;
247+
}
248+
249+
public Builder age(int age) {
250+
this.age = age;
251+
return this;
252+
}
253+
254+
public Builder num(int num) {
255+
this.num = num;
256+
return this;
257+
}
258+
259+
public Builder email(String email) {
260+
this.email = email;
261+
return this;
262+
}
263+
264+
public Student build() {
265+
// 将builder对象传入到学生构造函数
266+
return new Student(this);
267+
}
268+
}
269+
// 私有化构造器
270+
private Student(Builder builder) {
271+
name = builder.name;
272+
age = builder.age;
273+
num = builder.num;
274+
email = builder.email;
83275
}
84-
//...
276+
85277
@Override
86-
public Computer getComputer() {
87-
return computer;
278+
public String toString() {
279+
return "Student{" +
280+
"name='" + name + '\'' +
281+
", age=" + age +
282+
", num=" + num +
283+
", email='" + email + '\'' +
284+
'}';
88285
}
89286
}
287+
```
90288

91-
Computer computer=new Computer.Builder("因特尔","三星")
92-
.setDisplay("三星24寸")
93-
.setKeyboard("罗技")
94-
.setUsbCount(2)
95-
.build();
289+
调用代码:
290+
291+
```java
292+
public static void student(){
293+
Student student = Student.builder().name("平头哥").num(1).age(18).email("平头哥@163.com").build();
294+
System.out.println(student);
295+
}
96296
```
297+
298+
可以看到,变种 Builder 模式包括以下内容:
299+
300+
- 在要构建的类内部创建一个静态内部类 Builder
301+
- 静态内部类的参数与构建类一致
302+
- 构建类的构造参数是 静态内部类,使用静态内部类的变量一一赋值给构建类
303+
- 静态内部类提供参数的 setter 方法,并且返回值是当前 Builder 对象
304+
- 最终提供一个 build 方法构建一个构建类的对象,参数是当前 Builder 对象
305+
306+
可能你会说,这种写法实现太麻烦了,确实需要我们写很多额外的代码,好在前辈们已经开发出了`lombok`来拯救我们,我们只需要引入`lombok`插件,然后在实体类上添加`@Builder`注解,你就可以使用 Builder 模式构建对象了。
307+
308+
## 建造者模式的优缺点
309+
310+
### 优点
311+
312+
- 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
313+
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
314+
- 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
315+
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合"开闭原则"
316+
317+
### 缺点
318+
319+
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
320+
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /