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 coldDishes;

/**

* 热菜类

*/

private List 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 goodsList) {

float result = 0.0f;

for (Goods goods : goodsList) {

result += goods.getPrice();

}

return result;

}

/**

* 展示单类菜品菜单

* @param goodsList

*/

private void showSingleDishesName(List 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 coldDishes = new ArrayList<>(1);

coldDishes.add(new BoiledPeanuts());

mealBuilder.setColdDishes(coldDishes);

//热菜

List hotDishes = new ArrayList(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 coldDishes = new ArrayList<>(1);

coldDishes.add(new FriedPeanuts());

mealBuilder.setColdDishes(coldDishes);

//热菜

List hotDishes = new ArrayList(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

四、建造者模式结构

61fee5ad199e4ff4c4687f6b84b35a61.png生成器 (Builder) 接口声明在所有类型生成器中通用的产品构造步骤。

具体生成器 (Concrete Builders) 提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。

产品 (Products) 是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。

主管 (Director) 类定义调用构造步骤的顺序, 这样就可以创建和复用特定的产品配置。

客户端 (Client) 必须将某个生成器对象与主管类关联。 一般情况下, 只需通过主管类构造函数的参数进行一次性关联即可。 此后主管类就能使用生成器对象完成后续所有的构造任务。 但在客户端将生成器对象传递给主管类制造方法时还有另一种方式。 在这种情况下,在使用主管类生产产品时每次都可以使用不同的生成器。

设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值