java设计模式-建造者模式

138 阅读2分钟

试想这样一个装修业务(吊顶、涂料),由于吊顶、涂料种类很多,因此可以组合成一些套餐。

主接口类:

public interface Matter {
    String scene(); // 场景:涂料、吊顶

    String brand(); //品牌

    String model(); //型号

    BigDecimal price(); //价格

    String desc(); // 描述

}

吊顶实现类:

public class LevelOneCeiling implements Matter{

    @Override
    public String scene() {
        return "吊顶";
    }

    @Override
    public String brand() {
        return "装修公司自带";
    }

    @Override
    public String model() {
        return "一级顶";
    }

    @Override
    public BigDecimal price() {
        return new BigDecimal(260);
    }

    @Override
    public String desc() {
        return "一级顶,离顶120-150mm";
    }
}
public class LevelTwoCeiling implements Matter {
    @Override
    public String scene() {
        return "吊顶";
    }

    @Override
    public String brand() {
        return "装修公司自带";
    }

    @Override
    public String model() {
        return "二级顶";
    }

    @Override
    public BigDecimal price() {
        return new BigDecimal(850);
    }

    @Override
    public String desc() {
        return "二级顶,往下吊20cm";
    }
}

涂料实现类:

public class DuluxCoat implements Matter {
    @Override
    public String scene() {
        return "涂料";
    }

    @Override
    public String brand() {
        return "多乐士";
    }

    @Override
    public String model() {
        return "第二代";
    }

    @Override
    public BigDecimal price() {
        return new BigDecimal(719);
    }

    @Override
    public String desc() {
        return "多乐士涂料";
    }
}
public class LiBangCoat implements Matter {
    @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 desc() {
        return "立邦涂料";
    }
}

套餐类:

//如果不止这三种套餐我们是不是得写很多if代码块呢?
public class DecorationPackageController {
    public String getMatterList(BigDecimal area,Integer level){
        List<Matter> list = new ArrayList<>();
        BigDecimal price = BigDecimal.ZERO;

        //套餐1
        if(1 == level){
            LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling();
            DuluxCoat duluxCoat = new DuluxCoat();
           
            list.add(levelTwoCeiling);
            list.add(duluxCoat);
            

            price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));
            price = price.add(area.multiply(new BigDecimal("1.4")).multiply(duluxCoat.price()));
        }

        // 套餐2
        if (2 == level) {

            LevelTwoCeiling levelTwoCeiling = new LevelTwoCeiling();
            LiBangCoat liBangCoat = new LiBangCoat();                
           

            list.add(levelTwoCeiling);
            list.add(liBangCoat);
            

            price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelTwoCeiling.price()));
            price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.price()));
            
        }

        // 套餐3
        if (3 == level) {

            LevelOneCeiling levelOneCeiling = new LevelOneCeiling(); 
            LiBangCoat liBangCoat = new LiBangCoat();                
            
            list.add(levelOneCeiling);
            list.add(liBangCoat);
           

            price = price.add(area.multiply(new BigDecimal("0.2")).multiply(levelOneCeiling.price()));
            price = price.add(area.multiply(new BigDecimal("1.4")).multiply(liBangCoat.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();
    }

测试类:

@Test
public void test_DecorationPackageController(){
   DecorationPackageController decoration = new DecorationPackageController();
   
   System.out.println(decoration.getMatterList(new BigDecimal("132.52"),1));
   
   System.out.println(decoration.getMatterList(new BigDecimal("98.25"),2));
  
   System.out.println(decoration.getMatterList(new BigDecimal("85.43"),3));
}

开始说实现三种套餐,我们很容易用if代码块实现,但是如果有十几种套餐呢?我们是不是得在一个类中写很多if代码块,这样不是说不好,功能起码实现了。但是一个类逻辑过于复杂不好维护。 我们可以这样想一个套餐是由两大类吊顶和涂料两个小种类组成的,这是不是可以用建造者模式进行改造。 建造者的核心是一个填充各种小种类的方法类,一个builder类来构建套餐。

填充种类方法接口:

public interface IMenu {
    IMenu appendCeiling(Matter matter); //吊顶

    IMenu appendCoat(Matter matter);//涂料

    String getDetail();
}

填充种类方法实现类:

@NoArgsConstructor
public class DecorationPackageMenu implements IMenu {
    private List<Matter> list = new ArrayList<>();//装修清单

    private BigDecimal price = BigDecimal.ZERO;

    private BigDecimal area; //面积

    private String grade; //套餐

    public DecorationPackageMenu(BigDecimal area, String grade) {
        this.area = 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 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类:

public class Builder {

    public IMenu levelOne(BigDecimal area) {
        return new DecorationPackageMenu(area, "套餐1")
                .appendCeiling(new LevelTwoCeiling())
                .appendCoat(new DuluxCoat());
    }

    public IMenu levelTwo(BigDecimal area){
        return new DecorationPackageMenu(area, "套餐2")
                .appendCeiling(new LevelTwoCeiling())
                .appendCoat(new LiBangCoat());
    }

    public IMenu levelThree(BigDecimal area){
        return new DecorationPackageMenu(area, "套餐3")
                .appendCeiling(new LevelOneCeiling())
                .appendCoat(new LiBangCoat());
    }
}

测试方法:

@Test
public void test_Builder(){
   Builder builder = new Builder();
   // 套餐1
   System.out.println(builder.levelOne(new BigDecimal("132.52")).getDetail());
   // 套餐2
   System.out.println(builder.levelTwo(new BigDecimal("98.25")).getDetail());
   // 套餐3
   System.out.println(builder.levelThree(new BigDecimal("85.43")).getDetail());
}

以后再想新增套餐类就可以在bulider类里直接添加就可以了,构建者模式用来搞一个复杂对象的(由很多小种类对象组成)。