乐趣区

关于java:初学-Java-设计模式四实战建造者模式-单人年夜饭套餐

一、建造者模式介绍

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
@Setter
public 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…

退出移动版