开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 3 天,点击查看活动详情
建造者模式
将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。「大话设计模式」
Java 中 StringBuilder#append 就是一个建造者模式
原型实战
买房子,需要请装修公司服务,(虽然我买不起房子)那么装修公司可以看成一个大对象,里面由吊顶、涂料、地板、地砖等组成。并且这些物品都有不同的类型和档次。
我们只需要选几档就能创出装修公司这么一个对象。
/**
* 提供了基本信息,保证所有的装修材料都可以按照统一标准进行获取
*/
public interface Matter {
String scence();//场景:地板/地砖/涂料/吊顶
String brand();//品牌
String model();//型号
BigDecimal price();//价格
String desc();//描述
}
//一级吊顶
public class LevelOneCeiling implements Matter {
@Override
public String scence() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司自带";
}
@Override
public String model() {
return "一级顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(100);
}
@Override
public String desc() {
return "一级顶,比较便宜些";
}
}
//二级吊顶
public class LevelTwoCeiling implements Matter {
@Override
public String scence() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司自带";
}
@Override
public String model() {
return "二级顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(200);
}
@Override
public String desc() {
return "二级顶,更加豪华";
}
}
类似的还有地板、地砖、涂料等。
下面是测试类:我们选了档次,然后挨个创建对象并且组装成一个大对象。并最终输出结果
public class TestController {
public static void main(String[] args) {
String result = getMatterList(BigDecimal.valueOf(132.52), 1);
System.out.println(result);
}
public static String getMatterList(BigDecimal bigDecimal, 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(levelTwoCeiling.price());
price = price.add(duluxCoat.price());
price = price.add(shengXiangFloor.price());
}else if(2==level){
//另外的吊顶、涂料、地板、地砖
}else if(3==level){
//xxx
}
StringBuilder detail = new StringBuilder("\r\n-----\r\n"+
"装修清单" + "\r\n" +
"套餐等级:"+level+"\r\n"+
"套餐价格:"+price.setScale(2,BigDecimal.ROUND_HALF_UP)+
" 元\r\n"+
"房屋面积:"+bigDecimal.doubleValue()+"平米\r\n"+
"材料清单:"+"\r\n");
for(Matter matter:list){
detail.append(matter.scence()).append(":").append(matter.brand()).append("、").
append(matter.model()).append("、平米价:").append(matter.price()).
append(" 元。\n");
}
return detail.toString();
}
建造者模式
public interface IMenu {
IMenu appendCeiling(Matter matter);//吊顶
IMenu appendCoat(Matter matter);//涂料
IMenu appendFloor(Matter matter); // 地板
IMenu appendTile(Matter matter); // 地砖
String getDetail(); // 明细
}
public class Builder {
public IMenu levelOne(Double area) {
return new DecorationPackageMenu(area, "豪华欧式").appendTile(new DongPengTile())
.appendCeiling(new LevelTwoCeiling()) // 吊顶,⼆二级顶
.appendCoat(new DuluxCoat()) // 涂料料,多乐⼠士
.appendFloor(new ShengXiangFloor()); // 地板,圣象
}
//levelTwo
//....
}
public class DecorationPackageMenu implements IMenu{
private List<Matter> list = new ArrayList<Matter>(); //装修清单
private BigDecimal price = BigDecimal.ZERO; //装修价格
private BigDecimal area; //面积
private String grade; //装修等级
public DecorationPackageMenu() {
}
public DecorationPackageMenu(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 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.scence()).append(":").append(matter.brand()).append("、").
append(matter.model()).append("、平米价:").append(matter.price()).
append(" 元。\n");
}
return detail.toString();
}
}
从上面可以看出建造者模式,在创建的时候,可以很明确的知道我那些需要创建,可以直接提示,而且可以随意添加。不怕会漏掉什么东西。比如肯德基等快餐就是‘建造者’模式:一个牛肉汉堡=牛肉片+生菜+面包+芝士(这是基本的,必选)。如果客人有额外要求可以再继续添加东西。
DecorationPackageMenu 上面这个类中,在填充各个对象的时候,需要注意的点是直接返回了 this 。这样添加下一个对象的时候才会直接在此对象上添加。
总结
优点:一些基本对象不会变(而且不会遗忘),组合又会经常变化的情况下,可以选择。
缺点:组合的基本对象过多,会造成类膨胀。比如,我们上面只是囊括了装修的四个方面就建了8个类,甚至每个对象细分可能就有十几个,那就是十几倍。