文章目录
建造者模式(Builder Pattern)
建造者模式的定义
- 建造者模式(Builder Pattern)
- 建造者模式的定义
- 建造者模式的优点
- 建造者模式的缺点
- 建造者模式的结构
- 建造者模式的实现
- 物料部分
- 产品部分
- 建造类部分
- 指挥者部分
- 场景调用
- 使用场景
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
建造者模式的优点- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者(Builder)模式的主要角色如下。
- 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个滅部件。
- 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
- 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
- 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
package org.donny.design.patterns.builderPattern;
import java.math.BigDecimal;
/**
* 物料
*/
public interface IMatter {
/**
* 场景分别为地板、地砖、涂料、吊顶
*/
public String scene();
/**
* 品牌
*/
public String brand();
/**
* 型号
*/
public String model();
/**
* 平米报价
*/
public BigDecimal price();
/**
* 描述
*/
public String describe();
}
package org.donny.design.patterns.builderPattern.matter.ceiling;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 吊顶原料
* 品牌;装修公司自带
* 型号:一级顶
*/
public class OneLevelCeiling implements IMatter {
@Override
public String scene() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司";
}
@Override
public String model() {
return "一层顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(160);
}
@Override
public String describe() {
return "只有一个120-150mm层次的吊顶";
}
}
package org.donny.design.patterns.builderPattern.matter.ceiling;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 吊顶原料
* 品牌;装修公司自带
* 型号:二级顶
*/
public class TwoLevelCeiling implements IMatter {
@Override
public String scene() {
return "吊顶";
}
@Override
public String brand() {
return "装修公司";
}
@Override
public String model() {
return "二层顶";
}
@Override
public BigDecimal price() {
return new BigDecimal(650);
}
@Override
public String describe() {
return "二级吊顶高度一般就往下吊20cm,要是层高很高,也可增加每级的厚度";
}
}
package org.donny.design.patterns.builderPattern.matter.coat;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 涂料原料
* 品牌:多乐士(Dulux)
*/
public class DuluxCoat implements IMatter {
@Override
public String scene() {
return "涂料";
}
@Override
public String brand() {
return "多乐士(Dulux)";
}
@Override
public String model() {
return "第二代";
}
@Override
public BigDecimal price() {
return new BigDecimal(718);
}
@Override
public String describe() {
return "多乐士是阿克苏诺贝尔旗下的著名建筑装饰油漆品牌";
}
}
package org.donny.design.patterns.builderPattern.matter.coat;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 涂料
* 品牌;立邦
*/
public class LiBangCoat implements IMatter {
@Override
public String scene() {
return "涂料";
}
@Override
public String brand() {
return "立邦";
}
@Override
public String model() {
return "默认级别";
}
@Override
public BigDecimal price() {
return new BigDecimal(650);
}
@Override
public String describe() {
return "立邦";
}
}
package org.donny.design.patterns.builderPattern.matter.floor;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 地板原料
* 品牌;德尔(Der)
*/
public class DerFloor implements IMatter {
@Override
public String scene() {
return "地板";
}
@Override
public String brand() {
return "德尔(Der)";
}
@Override
public String model() {
return "A++";
}
@Override
public BigDecimal price() {
return new BigDecimal(119);
}
@Override
public String describe() {
return "DER木地板制造商";
}
}
package org.donny.design.patterns.builderPattern.matter.floor;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 地板原料
* 品牌:圣象
*/
public class ShengXiangFloor implements IMatter {
@Override
public String scene() {
return "地板";
}
@Override
public String brand() {
return "圣象";
}
@Override
public String model() {
return "一级";
}
@Override
public BigDecimal price() {
return new BigDecimal(328);
}
@Override
public String describe() {
return "圣象地板";
}
}
package org.donny.design.patterns.builderPattern.matter.tile;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 地砖原料
* 品牌:东鹏瓷砖
*/
public class DongPengTile implements IMatter {
@Override
public String scene() {
return "地砖";
}
@Override
public String brand() {
return "东鹏瓷砖";
}
@Override
public String model() {
return "10001";
}
@Override
public BigDecimal price() {
return new BigDecimal(112);
}
@Override
public String describe() {
return "东鹏瓷砖";
}
}
package org.donny.design.patterns.builderPattern.matter.tile;
import org.donny.design.patterns.builderPattern.IMatter ;
import java.math.BigDecimal;
/**
* 地砖原料
* 品牌;马可波罗(MARCO POLO)
*/
public class MarcoPoloTile implements IMatter {
@Override
public String scene() {
return "地砖";
}
@Override
public String brand() {
return "马可波罗 (MARCO POLO)";
}
@Override
public String model() {
return "缺省";
}
@Override
public BigDecimal price() {
return new BigDecimal(140);
}
@Override
public String describe() {
return "马可波罗品牌";
}
}
产品部分
package org.donny.design.patterns.builderPattern;
public class Menu {
private Matter celling;
private Matter coat;
private Matter floor;
private Matter tile;
private String getDetail;
public Matter getCelling() {
return celling;
}
public void setCelling(Matter celling) {
this.celling = celling;
}
public Matter getCoat() {
return coat;
}
public void setCoat(Matter coat) {
this.coat = coat;
}
public Matter getFloor() {
return floor;
}
public void setFloor(Matter floor) {
this.floor = floor;
}
public Matter getTile() {
return tile;
}
public void setTile(Matter tile) {
this.tile = tile;
}
public String getGetDetail() {
return getDetail;
}
public void setGetDetail(String getDetail) {
this.getDetail = getDetail;
}
}
建造类部分
public abstract class IMenuBuilder {
public abstract Menu getMenu();
}
public class LuxuryMenuBuilder extends IMenuBuilder {
private final Menu luxuryMenu = new Menu();
private final List list = new ArrayList();
/**
* 装修价格
*/
private BigDecimal price = BigDecimal.ZERO;
/**
* 面积
*/
private final BigDecimal area;
public LuxuryMenuBuilder(Double area) {
this.area = new BigDecimal(area);
this.luxuryMenu.setCelling(new TwoLevelCeiling());
this.price = this.price.add(this.area.multiply(new BigDecimal("0.2")).multiply(luxuryMenu.getCelling().price()));
this.luxuryMenu.setCoat(new DuluxCoat());
this.price = price.add(this.area.multiply(new BigDecimal("1.4")).multiply(luxuryMenu.getCoat().price()));
this.luxuryMenu.setFloor(new ShengXiangFloor());
this.list.add(luxuryMenu.getFloor());
this.list.add(luxuryMenu.getCoat());
this.list.add(luxuryMenu.getCelling());
this.luxuryMenu.setGetDetail(this.getDetail());
}
@Override
public Menu getMenu() {
return luxuryMenu;
}
public String getDetail() {
StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +
"装修清单" + "\r\n" +
"套餐等级:欧式\r\n" +
"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元\r\n" +
"房屋面积:" + area.doubleValue() + " 平米\r\n" +
"材料清单:\r\n");
for (Matter matter : this.list) {
detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。\n");
}
return detail.toString();
}
}
package org.donny.design.patterns.builderPattern;
import org.donny.design.patterns.builderPattern.matter.ceiling.LevelTwoCeiling;
import org.donny.design.patterns.builderPattern.matter.coat.LiBangCoat;
import org.donny.design.patterns.builderPattern.matter.tile.MarcoPoloTile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class LightLuxuryMenuBuilder extends IMenuBuilder {
private final Menu lightLuxuryMenu = new Menu();
private final List list = new ArrayList();
/**
* 装修价格
*/
private BigDecimal price = BigDecimal.ZERO;
/**
* 面积
*/
private final BigDecimal area;
public LightLuxuryMenuBuilder(Double area) {
this.area = new BigDecimal(area);
this.lightLuxuryMenu.setCelling(new TwoLevelCeiling());
this.price = this.price.add(this.area.multiply(new BigDecimal("0.2")).multiply(lightLuxuryMenu.getCelling().price()));
this.lightLuxuryMenu.setCoat(new LiBangCoat());
this.price = price.add(this.area.multiply(new BigDecimal("1.4")).multiply(lightLuxuryMenu.getCoat().price()));
this.lightLuxuryMenu.setTile(new MarcoPoloTile());
this.list.add(this.lightLuxuryMenu.getTile());
this.list.add(this.lightLuxuryMenu.getCoat());
this.list.add(this.lightLuxuryMenu.getCelling());
this.lightLuxuryMenu.setGetDetail(this.getDetail());
}
@Override
public Menu getMenu() {
return this.lightLuxuryMenu;
}
public String getDetail() {
StringBuilder detail = new StringBuilder("\r\n-------------------------------------------------------\r\n" +
"装修清单" + "\r\n" +
"套餐等级:田园"+ "\r\n" +
"套餐价格:" + price.setScale(2, BigDecimal.ROUND_HALF_UP) + " 元"+"\r\n" +
"房屋面积:" + area.doubleValue() + " 平米"+"\r\n" +
"材料清单:"+"\r\n");
for (Matter matter : this.list) {
detail.append(matter.scene()).append(":").append(matter.brand()).append("、").append(matter.model()).append("、平米价格:").append(matter.price()).append(" 元。");
}
return detail.toString();
}
}
指挥者部分
public class Director {
public Menu getLuxuryMenu(Double area) {
return new LuxuryMenuBuilder(area).getMenu();
}
public Menu getLightLuxuryMenu(Double area) {
return new LightLuxuryMenuBuilder(area).getMenu();
}
}
场景调用
public class Client {
public static void main(String[] args) {
Director director =new Director();
System.out.println(director.getLightLuxuryMenu(132.52D).getGetDetail());
System.out.println(director.getLuxuryMenu(98.25D).getGetDetail());
}
}
使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
- 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。该种场景只能是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟然没有发觉,而要通过创建者模式柔化创建过程,本身已经违反设计的最初目标。
本文主要参考:
- 小傅哥的《重学Java模式》
- 《设计模式之禅》第二版 秦小波