一、建造者模式介绍

1. 解决的问题

次要解决在软件系统中,有时候面临着"一个简单对象"的创立工作,其通常由各个局部的子对象用肯定的算法形成;因为需要的变动,这个简单对象的各个局部常常面临着激烈的变动,然而将它们组合在一起的算法却绝对稳固。

2. 定义

建造者模式是一种创立型设计模式,可能分步骤创立简单对象。该模式容许应用雷同的创立代码生成不同类型和模式的对象。

建造者模式利用于一些根本组件不变,而其组合常常变动时,此时能够将变与不变分来到。由建造者创立和提供实例,主管者治理建造进去的实例的依赖关系。

二、建造者模式优缺点

1. 长处

  • 能够分步创建对象,暂缓创立步骤或递归运行创立步骤。
  • 生成不同模式的产品时,你能够复用雷同的制作代码。
  • 繁多职责准则:能够将简单结构代码从产品的业务逻辑中分离出来。

2. 毛病

  • 因为采纳该模式须要新增多个类,因而代码整体复杂程度会有所增加。

三、建造者模式利用实例:单人年夜饭套餐

1. 实例场景

往年很多人都响应了就地过年的倡导,但异地过年不心酸,咱们能够点一份单人年夜饭套餐来犒劳异地过年的本人!

单人多肉年夜饭套餐:

  • 凉菜类:水煮花生
  • 热菜类:宫保鸡丁、农家小炒肉、地锅鸡、土家红烧肉
  • 主食类:米饭
  • 饮品:崂山啤酒

单人混合肉蔬年夜饭套餐:

  • 凉菜类:油炸花生米
  • 热菜类:木须肉、椒盐里脊、手撕包菜、地三鲜
  • 主食类:米饭
  • 饮品:夺命大乌苏

2. 建造者模式实现

2.1 工程构造
builder-pattern└─ src    ├─ main    │    └─ java    │    └─ org.design.pattern.builder    │       ├─ model    │       │  └─ cold    │       │  │    ├─ BoiledPeanuts.java    │       │  │    └─ FriedPeanuts.java    │       │  └─ hot    │       │  │    ├─ KungPaoChicken.java    │       │  │    ├─ FarmhouseFriedPork.java    │       │  │    ├─ LocalPotChicken.java    │       │  │    ├─ TujiaBraisedPork.java    │       │  │    ├─ MushuMeat.java    │       │  │    ├─ SaltPepperTenderloin.java    │       │  │    ├─ ShreddedCabbage.java    │       │  │    └─ DiSanXian.java    │       │  └─ staple    │       │  │    └─ Rice.java    │       │  └─ drink    │       │  │    ├─ LaoShanBeer.java    │       │  │    └─ WuSuBeer.java    │       │  └─ Goods.java    │       ├─ builders    │       │    └─ MealBuilder.java        │       └─ director    │           └─ MealDirector.java    └─ test        └─ java            └─ org.design.pattern.builder.test                  └─ MealDirectorTest.java
2.2 代码实现
2.2.1 菜品

菜品接口

所有菜都须要提供菜名以及价格。

/** * 菜品 */public interface Goods {    String getName();    float getPrice();}

水煮花生

/** * 水煮花生 */public class BoiledPeanuts implements Goods {    @Override    public String getName() {        return "水煮花生";    }    @Override    public float getPrice() {        return 8;    }}
2.2.2 年夜饭生成器
/** * 年夜饭生成器 */@Getter@Setterpublic class MealBuilder {    /**     * 冷菜类     */    private List<Goods> coldDishes;    /**     * 热菜类     */    private List<Goods> hotDishes;    /**     * 主食     */    private Goods stapleFood;    /**     * 饮料     */    private Goods drink;    /**     * 获取花销     * @return     */    public float getCost() {        float result = 0.0f;        result += getSingleDishesCost(coldDishes);        result += getSingleDishesCost(hotDishes);        result += stapleFood.getPrice();        result += drink.getPrice();        return result;    }    /**     * 展现菜单     */    public void showMenu() {        System.out.println("凉菜类:");        showSingleDishesName(coldDishes);        System.out.println("热菜类:");        showSingleDishesName(hotDishes);        System.out.println("主食:");        System.out.println(stapleFood.getName());        System.out.println("饮料:");        System.out.println(drink.getName());    }    /**     * 获取单类菜品价格     * @param goodsList     * @return     */    private float getSingleDishesCost(List<Goods> goodsList) {        float result = 0.0f;        for (Goods goods : goodsList) {            result += goods.getPrice();        }        return result;    }    /**     * 展现单类菜品菜单     * @param goodsList     */    private void showSingleDishesName(List<Goods> goodsList) {        for (Goods goods : goodsList) {            System.out.println(goods.getName());        }    }}
2.2.3 年夜饭主管类
/** * 年夜饭主管类 */public class MealDirector {    /**     * 单人多肉年夜饭套餐     * @return     */    public MealBuilder constructMeatDinner() {        MealBuilder mealBuilder = new MealBuilder();        //冷菜        List<Goods> coldDishes = new ArrayList<>(1);        coldDishes.add(new BoiledPeanuts());        mealBuilder.setColdDishes(coldDishes);        //热菜        List<Goods> hotDishes = new ArrayList<Goods>(4);        hotDishes.add(new KungPaoChicken());        hotDishes.add(new FarmhouseFriedPork());        hotDishes.add(new LocalPotChicken());        hotDishes.add(new TujiaBraisedPork());        mealBuilder.setHotDishes(hotDishes);        //主食        mealBuilder.setStapleFood(new Rice());        //饮料        mealBuilder.setDrink(new LaoShanBeer());        return mealBuilder;    }    /**     * 单人混合肉蔬年夜饭套餐     * @return     */    public MealBuilder constructMeanAndVegetablesDinner() {        MealBuilder mealBuilder = new MealBuilder();        //冷菜        List<Goods> coldDishes = new ArrayList<>(1);        coldDishes.add(new FriedPeanuts());        mealBuilder.setColdDishes(coldDishes);        //热菜        List<Goods> hotDishes = new ArrayList<Goods>(4);        hotDishes.add(new MushuMeat());        hotDishes.add(new SaltPepperTenderloin());        hotDishes.add(new ShreddedCabbage());        hotDishes.add(new DiSanXian());        mealBuilder.setHotDishes(hotDishes);        //主食        mealBuilder.setStapleFood(new Rice());        //饮料        mealBuilder.setDrink(new WuSuBeer());        return mealBuilder;    }}
2.3 测试验证
2.3.1 测试验证类
public class MealDirectorTest {    @Test    public void testConstructMeatDinner() {        MealDirector mealDirector = new MealDirector();        MealBuilder mealBuilder = mealDirector.constructMeatDinner();        mealBuilder.showMenu();        System.out.println("单人多肉年夜饭套餐破费:" + mealBuilder.getCost());    }    @Test    public void testConstructMeanAndVegetablesDinner() {        MealDirector mealDirector = new MealDirector();        MealBuilder mealBuilder = mealDirector.constructMeanAndVegetablesDinner();        mealBuilder.showMenu();        mealBuilder.getCost();        System.out.println("单人混合肉蔬年夜饭套餐:" + mealBuilder.getCost());    }}
2.3.2 测试后果
凉菜类:水煮花生热菜类:宫保鸡丁农家小炒肉地锅鸡土家红烧肉主食:米饭饮料:崂山啤酒单人多肉年夜饭套餐破费:141.0凉菜类:油炸花生米热菜类:木须肉椒盐里脊手撕包菜地三鲜主食:米饭饮料:夺命大乌苏单人混合肉蔬年夜饭套餐:112.0

四、建造者模式构造

  1. 生成器 (Builder) 接口申明在所有类型生成器中通用的产品结构步骤。
  2. 具体生成器 (Concrete Builders) 提供结构过程的不同实现。 具体生成器也能够结构不遵循通用接口的产品。
  3. 产品 (Products) 是最终生成的对象。 由不同生成器结构的产品无需属于同一类层次结构或接口。
  4. 主管 (Director) 类定义调用结构步骤的程序, 这样就能够创立和复用特定的产品配置。
  5. 客户端 (Client) 必须将某个生成器对象与主管类关联。 个别状况下, 只需通过主管类构造函数的参数进行一次性关联即可。 尔后主管类就能应用生成器对象实现后续所有的结构工作。 但在客户端将生成器对象传递给主管类制作办法时还有另一种形式。 在这种状况下,在应用主管类生产产品时每次都能够应用不同的生成器。

设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。

源码地址:https://github.com/yiyufxst/d...

参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei...
深刻设计模式:https://refactoringguru.cn/de...