设计模式-建造者模式
建造者模式
适用场景:
一些基本物料不会变,而其组合经常变化的时候,可以选择建造者模式来改造代码
案例:模拟装修公司对于设计出一些套餐装修服务的场景
装修物料接口:Matter
/**
* 装修物料
*/
public interface Matter {
/**
* 场景;地板、地砖、涂料、吊顶
*/
String scene();
/**
* 品牌
*/
String brand();
/**
* 型号
*/
String model();
/**
* 平米报价
*/
BigDecimal price();
/**
* 描述
*/
String desc();
}
吊顶(ceiling)
-
一级顶
/** * 吊顶 * 品牌;装修公司自带 * 型号:一级顶 */ public class LevelOneCeiling implements Matter { public String scene() { return "吊顶"; } public String brand() { return "装修公司自带"; } public String model() { return "一级顶"; } public BigDecimal price() { return new BigDecimal(260); } public String desc() { return "造型只做低一级,只有一个层次的吊顶,一般离顶120-150mm"; } }
-
二级顶
public class LevelTwoCeiling implements Matter { public String scene() { return "吊顶"; } public String brand() { return "装修公司自带"; } public String model() { return "二级顶"; } public BigDecimal price() { return new BigDecimal(850); } public String desc() { return "两个层次的吊顶,二级吊顶高度一般就往下吊20cm,要是层高很高,也可增加每级的厚度"; } }
涂料
-
多乐土
/** * 涂料 * 品牌;多乐士(Dulux) */ public class DuluxCoat implements Matter { public String scene() { return "涂料"; } public String brand() { return "多乐士(Dulux)"; } public String model() { return "第二代"; } public BigDecimal price() { return new BigDecimal(719); } public String desc() { return "多乐士是阿克苏诺贝尔旗下的著名建筑装饰油漆品牌,产品畅销于全球100个国家,每年全球有5000万户家庭使用多乐士油漆。"; } }
-
立邦
public class LiBangCoat implements Matter { public String scene() { return "涂料"; } public String brand() { return "立邦"; } public String model() { return "默认级别"; } public BigDecimal price() { return new BigDecimal(650); } public String desc() { return "立邦始终以开发绿色产品、注重高科技、高品质为目标,以技术力量不断推进科研和开发,满足消费者需求。"; } }
然后是地板的几个品牌,地砖的几个品牌,和上边一样,实现matter接口
ifelse实现
public class DecorationPackageController {
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();
}
}
通过传递的参数来判断是做什么风格的装修,然后分别单独构建装修材料,然后组合起来,计算价格
建造者模式重构代码
工程结构如图:
建造者模型结构:
- Builder类,建造者类具体的各类组装由此类实现。
- DecorationPackageMenu类,实现Imenu接口,通过list放置要装修的材料,保存价格的变量,装修风格的变量和面积的变量都是通过构造函数的参数传递进来
代码实现:
-
Imenu接口:
public interface IMenu { /** * 吊顶 */ IMenu appendCeiling(Matter matter); /** * 涂料 */ IMenu appendCoat(Matter matter); /** * 地板 */ IMenu appendFloor(Matter matter); /** * 地砖 */ IMenu appendTile(Matter matter); /** * 明细 */ String getDetail(); }
接口类中定义了填充各项物料的方法; 吊顶 、 涂料 、 地板 、 地砖 ,以及最终提供获取全部明细的方法。
-
装修包的实现
public class DecorationPackageMenu implements IMenu { 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 IMenu appendCeiling(Matter matter) { list.add(matter); price = price.add(area.multiply(new BigDecimal("0.2")).multiply(matter.price())); return this; } public IMenu appendCoat(Matter matter) { list.add(matter); price = price.add(area.multiply(new BigDecimal("1.4")).multiply(matter.price())); return this; } public IMenu appendFloor(Matter matter) { list.add(matter); price = price.add(area.multiply(matter.price())); return this; } public IMenu appendTile(Matter matter) { list.add(matter); price = price.add(area.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(); } }
- 装修包的实现中每一个方法都返回了 this ,也就可以非常方便的用于连续填充各项物料
- 同时在填充时也会根据物料计算平米数下的报价,吊顶和涂料按照平米数乘以该类定义的price计算
- 最后同样提供了统一的获取装修清单的明细方法。
-
建造者方法
public class Builder { public IMenu levelOne(Double area) { return new DecorationPackageMenu(area, "豪华欧式") .appendCeiling(new LevelTwoCeiling()) // 吊顶,二级顶 .appendCoat(new DuluxCoat()) // 涂料,多乐士 .appendFloor(new ShengXiangFloor()); // 地板,圣象 } public IMenu levelTwo(Double area){ return new DecorationPackageMenu(area, "轻奢田园") .appendCeiling(new LevelTwoCeiling()) // 吊顶,二级顶 .appendCoat(new LiBangCoat()) // 涂料,立邦 .appendTile(new MarcoPoloTile()); // 地砖,马可波罗 } public IMenu levelThree(Double area){ return new DecorationPackageMenu(area, "现代简约") .appendCeiling(new LevelOneCeiling()) // 吊顶,二级顶 .appendCoat(new LiBangCoat()) // 涂料,立邦 .appendTile(new DongPengTile()); // 地砖,东鹏 } }
统一的建造⽅方式,通过不同物料填充出不同的装修风格; 豪华欧式 、 轻奢⽥田园 、 现代简约等
编写测试类
public class ApiTest {
@Test
public void test_Builder(){
Builder builder = new Builder();
// 豪华欧式
System.out.println(builder.levelOne(132.52D).getDetail());
// 轻奢田园
System.out.println(builder.levelTwo(98.25D).getDetail());
// 现代简约
System.out.println(builder.levelThree(85.43D).getDetail());
}
}