JAVA【设计模式】建造者模式
一、定义
建造者模式指的是一个复杂
对象,它是由多个简单
的对象组合,然后一步一步建构而成的
二、示例:
模拟场景:
很多装修公司都会给出⾃家的套餐服务,⼀般有;欧式豪华、轻奢⽥园、现代简约等等,⽽这些套餐的后⾯是不同的商品的组合。例如;⼀级&⼆级吊顶、多乐⼠涂料、圣象地板、⻢可波罗地砖等等,按照不同的套餐的价格选取不同的品牌组合,最终再按照装修⾯积给出⼀个整体的报价。
这⾥我们就模拟装修公司想推出⼀些套餐装修服务,按照不同的价格设定品牌选择组合,以达到使⽤建造者模式的过程。
传统硬编码方式(都在一个类里面实现,多重if else嵌套使用)
装修风格类:DecorationPackageController
package com.qf.design.create.builder.tradition;
import com.qf.design.create.builder.entity.Matter;
import com.qf.design.create.builder.entity.ceiling.LevelOneCeiling;
import com.qf.design.create.builder.entity.ceiling.LevelTwoCeiling;
import com.qf.design.create.builder.entity.coat.DuluxCoat;
import com.qf.design.create.builder.entity.coat.LiBangCoat;
import com.qf.design.create.builder.entity.floor.ShengXiangFloor;
import com.qf.design.create.builder.entity.tile.DongPengTile;
import com.qf.design.create.builder.entity.tile.MarcoPoloTile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
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();
}
}
测试:ApiTest
package com.qf.design.create.builder.tradition;
import java.math.BigDecimal;
public class ApiTest {
public static void main(String[] args) {
DecorationPackageController controller=new DecorationPackageController();
String matterList = controller.getMatterList(new BigDecimal(125.6), 1);
System.out.println(matterList);
}
}
建造者模式
任何的装修风格都是离不开基础的涂料、平层、瓷砖、吊顶。
抽象装修菜单接口:IMenu
package com.qf.design.create.builder.design;
import com.qf.design.create.builder.entity.Matter;
public interface IMenu {
/**
* 吊顶
*/
IMenu appendCeiling(Matter matter);
/**
* 涂料
*/
IMenu appendCoat(Matter matter);
/**
* 平层
*/
IMenu appendFloor(Matter matter);
/**
* 瓷砖
*/
IMenu appendTile(Matter matter);
/**
* 获取价格
*/
String getPrice();
}
规则实现:DecoratePackageMenu
package com.qf.design.create.builder.design;
import com.qf.design.create.builder.entity.Matter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class DecoratePackageMenu implements IMenu {
private List<Matter> list = new ArrayList<Matter>();
private BigDecimal area;
private String grade;
private BigDecimal price=BigDecimal.ZERO;
public DecoratePackageMenu(Double area,String grade){
this.area=new BigDecimal(area);
this.grade=grade;
}
@Override
public IMenu appendCeiling(Matter matter) {
list.add(matter);
price=price.add(area.multiply(new BigDecimal("0.2")).multiply(matter.price()));
return this;
}
@Override
public IMenu appendCoat(Matter matter) {
list.add(matter);
price=price.add(area.multiply(new BigDecimal("1.4")).multiply(matter.price()));
return this;
}
@Override
public IMenu appendFloor(Matter matter) {
list.add(matter);
price=price.add(area.multiply(matter.price()));
return this;
}
@Override
public IMenu appendTile(Matter matter) {
list.add(matter);
price=price.add(area.multiply(matter.price()));
return this;
}
@Override
public String getPrice() {
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 com.qf.design.create.builder.design;
import com.qf.design.create.builder.entity.ceiling.LevelOneCeiling;
import com.qf.design.create.builder.entity.ceiling.LevelTwoCeiling;
import com.qf.design.create.builder.entity.coat.DuluxCoat;
import com.qf.design.create.builder.entity.coat.LiBangCoat;
import com.qf.design.create.builder.entity.floor.ShengXiangFloor;
import com.qf.design.create.builder.entity.tile.DongPengTile;
import com.qf.design.create.builder.entity.tile.MarcoPoloTile;
public class Builder {
/**
* 一级品
* @param area
* @return
*/
public IMenu levelOne(Double area){
return new DecoratePackageMenu(area,"豪华欧式")
.appendCeiling(new LevelTwoCeiling())
.appendCeiling(new DuluxCoat())
.appendCeiling(new ShengXiangFloor());
}
/**
* 三级品
* @param area
* @return
*/
public IMenu levelTwo(Double area){
return new DecoratePackageMenu(area,"轻奢田园")
.appendCeiling(new LevelTwoCeiling())
.appendCeiling(new LiBangCoat())
.appendCeiling(new MarcoPoloTile());
}
/**
* 二级品
* @param area
* @return
*/
public IMenu levelThree(Double area){
return new DecoratePackageMenu(area,"现代简约")
.appendCeiling(new LevelOneCeiling())
.appendCeiling(new LiBangCoat())
.appendCeiling(new DongPengTile());
}
}
总结:
通过上⾯对建造者模式的使⽤,已经可以摸索出⼀点⼼得。那就是什么时候会选择这样的设计模
式,当: ⼀些基本物料不会变
,⽽其组合经常变化
的时候 ,就可以选择这样的设计模式来构建代码。
此设计模式满⾜了单⼀职责
原则以及可复⽤的技术、建造者独⽴
、易扩展
、便于控制细节⻛险。但
同时当出现特别多的物料以及很多的组合后,类的不断扩展也会造成难以维护的问题。但这种设计
结构模型可以把᯿复的内容抽象到数据库中,按照需要配置。这样就可以减少代码中⼤量的᯿复。