
上QQ阅读APP看书,第一时间看更新
2.5 应用建造者模式
建造者设计模式是最有用的创建型模式之一,因为它将较小的对象构建成较大的对象。这正是我们想要做的——从原料列表中构建出一个三明治对象。建造者模式还有一个更大的优势,就是以后可以很容易地增加可选功能。和以前一样,先要创建一个称为Ingredient的接口,并用它来表示Bread和Filling。这一次需要将热值表示为整数类型,因为我们需要计算成品三明治的总热量。
打开一个Android Studio项目或启动一个新项目,然后按照以下步骤创建一个基本的三明治建造者模式。
(1)创建一个名为Ingredient.java的新接口,用如下代码实现:
public interface Ingredient { String name(); int calories(); }
(2)创建一个名为Bread的抽象类:
public abstract class Bread implements Ingredient { @Override public abstract String name(); @Override public abstract int calories(); }
(3)创建一个一样的抽象类——Filling。
(4)接下来,创建Bread的具体类: public class Bagel extends Bread { @Override public String name() { return "Bagel"; } @Override public int calories() { return 250; } }
(5)对Filling类进行相同的操作。每种类型定义两个类,已经足够达到演示的目的:
public class SmokedSalmon extends Filling { @Override public String name() { return "Smoked salmon"; } @Override public int calories() { return 400; } }
(6)现在可以创建Sandwich类:
public class Sandwich { private static final String DEBUG_TAG = "tag"; //创建持有原料的列表 private List<Ingredient> ingredients = new ArrayList<Ingredient>(); //计算总热值 public void getCalories() { int c = 0; for (Ingredient i : ingredients) { c+= i.calories(); } Log.d(DEBUG_TAG, "Total calories : "+c+" kcal"); } //添加原料 public void addIngredient(Ingredient ingredient) { ingredients.add(ingredient); } //输出原料 public void getSandwich() { for (Ingredient i : ingredients) { Log.d(DEBUG_TAG, i.name()+" : "+i.calories()+" kcal"); } } }
(7)最后,创建SandwichBuilder类:
public class SandwichBuilder { //现成的三明治 public static Sandwich readyMade() { Sandwich sandwich = new Sandwich(); sandwich.addIngredient(new Bagel()); sandwich.addIngredient(new SmokedSalmon()); sandwich.addIngredient(new CreamCheese()); return sandwich; } //定制三明治 public static Sandwich build(Sandwich s, Ingredient i) { s.addIngredient(i); return s; } }
建造者设计模式已经完成,至少目前如此,如图2-12所示。

图2-12
这里,我们为建造者提供了两个功能:返回现成的三明治和用户定制的三明治。现在还没有可使用的界面,但是我们可以通过客户端代码模拟用户的选择。
我们还将输出的职责委托给了Sandwich类,这通常是一个明智的选择,因为这有助于保持客户端代码整洁和清晰,正如下边的代码所示:
//创建一个定制的三明治 SandwichBuilder builder = new SandwichBuilder(); Sandwich custom = new Sandwich(); //模拟用户的选择 custom = builder.build(custom, new Bun()); custom = builder.build(custom, new CreamCheese()); Log.d(DEBUG_TAG, "CUSTOMIZED"); custom.getSandwich(); custom.getCalories(); //创建一个现成的三明治 Sandwich offTheShelf = SandwichBuilder.readyMade(); Log.d(DEBUG_TAG, "READY MADE"); offTheShelf.getSandwich(); offTheShelf.getCalories();
代码将产生如下输出:
D/tag: CUSTOMIZED D/tag: Bun : 150 kcal D/tag: Cream cheese : 350 kcal D/tag: Total calories : 500 kcal D/tag: READY MADE D/tag: Bagel : 250 kcal D/tag: Smoked salmon : 400 kcal D/tag: Cream cheese : 350 kcal D/tag: Total calories : 1000 kcal
建造者最大的优点之一是非常容易添加、删除和修改具体类,甚至在修改接口或抽象类时,也不需要修改客户端源代码。这使得建造者模式成为最强大的模式之一,它可以在许多场景下使用。这并不是说,它总是比工厂模式更好。对于简单的对象,工厂模式通常是最好的选择。当然,模式存在于不同的尺度上,工厂模式嵌套在建造者模式中并不罕见,反之亦然。