什么是建造者模式
- 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
- 主要解决
主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 何时使用
一些基本部件不会变,而其组合经常变化的时候。
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。
- 如何解决:将变与不变分离开。
- 关键代码:
- 建造者:创建和提供实例
- 导演:管理建造出来的实例的依赖关系。
简单来说就是:通过将多个简单对象通过一步步的组装构建出一个复杂对象的过程。即一个复杂的对象拆分成多个简单对象进行组装构建
话不多说,上代码
-
案列描述
还是拿小傅哥的案例吧,用的是装修,源码地址:itstack-demo-design- 装修都需要的物料
- 构建各种套装,每个套装都是由上面的基本物料一个或者多个进行排列组合
- 装修都需要的物料
-
普通写法
public String getMatterList(BigDecimal area, Integer level) {
List<Matter> list = new ArrayList<Matter>(); // 装修清单
BigDecimal price = BigDecimal.ZERO; // 装修价格
// 豪华欧式
if (1 == level) {
LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling(); // 吊顶,二级顶
DuluxCoat duluxCoat = new DuluxCoat(); // 涂料,多乐士
ShengXiangFloor shengXiangFloor = new ShengXiangFloor(); // 地板,圣象
list.add(levelTwoCeiling);
list.add(duluxCoat);
list.add(shengXiangFloor);
price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));
price = price.add(area.multiply(new BigDecimal("1.4")).multiply(duluxCoat.price()));
price = price.add(area.multiply(shengXiangFloor.price()));
}
// 轻奢田园
if (2 == level) {
LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling(); // 吊顶,二级顶
LiBangCoat liBangCoat = new LiBangCoat(); // 涂料,立邦
MarcoPoloTile marcoPoloTile = new MarcoPoloTile(); // 地砖,马可波罗
list.add(levelTwoCeiling);
list.add(liBangCoat);
list.add(marcoPoloTile);
price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));
price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.price()));
price = price.add(area.multiply(marcoPoloTile.price()));
}
// 现代简约
if (3 == level) {
LevelOneCeiling levelOneCeiling = new LevelOneCeiling(); // 吊顶,二级顶
LiBangCoat liBangCoat = new LiBangCoat(); // 涂料,立邦
DongPengTile dongPengTile = new DongPengTile(); // 地砖,东鹏
list.add(levelOneCeiling);
list.add(liBangCoat);
list.add(dongPengTile);
price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelOneCeiling.price()));
price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.price()));
price = price.add(area.multiply(dongPengTile.price()));
}
StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +
"装修清单" + "\r\n" +
"套餐等级:" + level + "\r\n" +
"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元\r\n" +
"房屋面积:" + area.doubleValue() + " 平米\r\n" +
"材料清单:\r\n");
for (Matter matter: list) {
detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。\n");
}
return detail.toString();
}
-
建造者模式
···java
LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling(); // 吊顶,二级顶
DuluxCoat duluxCoat = new DuluxCoat(); // 涂料,多乐士
ShengXiangFloor shengXiangFloor = new ShengXiangFloor(); // 地板,圣象list.add(levelTwoCeiling); list.add(duluxCoat); list.add(shengXiangFloor); price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price())); price = price.add(area.multiply(new BigDecimal("1.4")).multiply(duluxCoat.price())); price = price.add(area.multiply(shengXiangFloor.price()));
-
普通写法基本上都是复用上面这个代码块 ,那如何优化简写呢?
-
结构说明
-
DecorationPackageMenu类
package org.itstack.demo.design;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 装修包
*/
public class DecorationPackageMenu {
// 装修清单(多个基础物料)
private List<Matter> list = new ArrayList<Matter>();
// 装修价格
private BigDecimal price = BigDecimal.ZERO;
// 面积
private BigDecimal area;
// 装修等级;豪华欧式、轻奢田园、现代简约
private String grade;
private DecorationPackageMenu() {
}
public DecorationPackageMenu(Double area, String grade) {
this.area = new BigDecimal(area);
this.grade = grade;
}
// 多个改成了单个
public DecorationPackageMenu appendMatter(Matter matter) {
list.add(matter);
price = price.add(area.multiply(new BigDecimal("0.2")).multiply(matter.price()));
return this;
}
public String getDetail() {
StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +
"装修清单" + "\r\n" +
"套餐等级:" + grade + "\r\n" +
"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元\r\n" +
"房屋面积:" + area.doubleValue() + " 平米\r\n" +
"材料清单:\r\n");
for (Matter matter: list) {
detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。\n");
}
return detail.toString();
}
}
- builder类
package org.itstack.demo.design;
import org.itstack.demo.design.ceiling.LevelOneCeiling;
import org.itstack.demo.design.ceiling.LevelTwoCeiling;
import org.itstack.demo.design.coat.DuluxCoat;
import org.itstack.demo.design.coat.LiBangCoat;
import org.itstack.demo.design.floor.ShengXiangFloor;
import org.itstack.demo.design.tile.DongPengTile;
import org.itstack.demo.design.tile.MarcoPoloTile;
public class Builder {
public DecorationPackageMenu levelOne(Double area) {
return new DecorationPackageMenu(area, "豪华欧式")
.appendMatter(new LevelTwoCeiling()) // 吊顶,二级顶
.appendMatter(new DuluxCoat()) // 涂料,多乐士
.appendMatter(new ShengXiangFloor()); // 地板,圣象
}
public DecorationPackageMenu levelTwo(Double area){
return new DecorationPackageMenu(area, "轻奢田园")
.appendMatter(new LevelTwoCeiling()) // 吊顶,二级顶
.appendMatter(new LiBangCoat()) // 涂料,立邦
.appendMatter(new MarcoPoloTile()); // 地砖,马可波罗
}
public DecorationPackageMenu levelThree(Double area){
return new DecorationPackageMenu(area, "现代简约")
.appendMatter(new LevelOneCeiling()) // 吊顶,二级顶
.appendMatter(new LiBangCoat()) // 涂料,立邦
.appendMatter(new DongPengTile()); // 地砖,东鹏
}
}
使用设计模式后,一眼就能看到有啥物料构成,也利于以后扩展
- 结尾–广告推广