设计模式之建造者模式
建造者模式的定义
“Separate the construction of a complex object from its representation so that the same construction process can create different representations. ”
(将一个复杂的对象的构建与他的表示分离,使得相同的构建过程可以创建不同的表示。)
在建造者模式中,有如下3个角色:
Ⅰ.Product产品类
通常是实现了模板方法模式,也就是有模板方法和基本方法。下图中的Hamburg以及Drink的实现类就属于产品类。
Ⅱ.Builder建造者
返回一个组建好的数据。下图中的MealBuilder旧数据建造者。
Ⅲ.Director导演类
负责调用MealBuilder,告诉它需要怎么样的产品。比如说需要吃素餐,就调用prepareVegMeal方法,需要吃鸡肉餐,就调用prepareChickenMeal方法。
package com.example.demo.designpatterns;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder builder = new MealBuilder();
Meal vegMeal = builder.prepareVegMeal();
vegMeal.showItems();
System.out.println("vegMeal cost money:" + vegMeal.getCost());
Meal chickenMeal = builder.prepareChickenMeal();
chickenMeal.showItems();
System.out.println("chickenMeal cost money:" + chickenMeal.getCost());
}
}
/**
* 创建一个表示食物条目和食物包装的接口。
*/
interface Item{
String name();
Packing packing();
BigDecimal price();
}
/**
* 打包方式
*/
interface Packing{
String pack();
}
/**
* 打包盒
*/
class Wrapper implements Packing{
@Override
public String pack() {
return "Wrapper";
}
}
class Bottle implements Packing{
@Override
public String pack() {
return "Bottle";
}
}
abstract class Hamburg implements Item{
@Override
public Packing packing(){
return new Wrapper();
}
}
class VegHamburg extends Hamburg{
@Override
public String name() {
return "蔬菜汉堡";
}
@Override
public BigDecimal price() {
return new BigDecimal(15);
}
}
class ChickenHamburg extends Hamburg{
@Override
public String name() {
return "鸡肉汉堡";
}
@Override
public BigDecimal price() {
return new BigDecimal(25);
}
}
abstract class Drink implements Item{
@Override
public Packing packing(){
return new Bottle();
}
}
class ColdDrink extends Drink{
@Override
public String name() {
return "冷饮";
}
@Override
public BigDecimal price() {
return new BigDecimal(10);
}
}
class WarmDrink extends Drink{
@Override
public String name() {
return "热饮";
}
@Override
public BigDecimal price() {
return new BigDecimal(15);
}
}
class MealBuilder{
public Meal prepareVegMeal(){
Meal meal = new Meal();
Item item = new VegHamburg();
Item item1 = new WarmDrink();
meal.addItem(item);
meal.addItem(item1);
return meal;
}
public Meal prepareChickenMeal(){
Meal meal = new Meal();
Item item = new ChickenHamburg();
Item item1 = new ColdDrink();
meal.addItem(item);
meal.addItem(item1);
return meal;
}
}
class Meal{
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item){
items.add(item);
}
public BigDecimal getCost(){
BigDecimal cost = BigDecimal.ZERO;
for (Item item : items) {
cost = cost.add(item.price());
}
return cost;
}
public void showItems(){
for (Item item : items) {
System.out.print("Item : "+item.name());
System.out.print(", Packing : "+item.packing().pack());
System.out.println(", price : "+item.price());
}
}
}
建造者模式的应用
-
建造者模式的优点
Ⅰ.封装性,使用建造者模式可以使客户不必知道产品内部组成的细节。
Ⅱ.建造者独立,容易扩展。
Ⅲ.便于控制细节风险。由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。 -
建造者模式的使用场景
Ⅰ.相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
Ⅱ.多个部件和零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
Ⅲ.产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
Ⅳ.在对象的创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。
建造者模式的注意事项
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大的不同的地方,虽然同为创建类模式,但是注重点不同。
建造者模式的最佳实践
在使用建造者模式的时候考虑一下模板方法模式,不要局限于思考一个模式,僵化的套用一个模式会让你受害无穷。