Skip to content

Commit 6b824ac

Browse files
committed
优惠券设计
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)