上一章节,我们终于在全国各地开满了我们的KFG餐厅连锁店,这一次我们要深入餐厅内部了。
我们将要了解顾客是如何点餐的。
按照正常情况来说,顾客来到店里,然后找到服务员,然后就开始点餐。
然后再点完餐后,服务员联系后厨按照订单完成客人所点的食物。然后所有点餐完成之后,将产品给我们的顾客。
我们理一理思路:
1.Waiter 等到顾客到店。
Waiter w = new Waiter();
2.然后Customer到店了。
Customer c = new Customer();
3.然后Customer找Waiter点餐。
嗯,我要一份炸鸡,还要一份薯条,嗯一份汉堡,我太饿了,再来一份汉堡
w.order(FoodType.Chicken).order(FoodType.Chip).order(FoodType.HAMBURGER).order(FoodType.HAMBURGER);
4.服务员从配餐员Pantryman得到所有的食物。
List<Food> foods = w.getFoods();
5.最后也是最重要的一步,那就是我们的Customer将食物全部给吃光了。
c.eatFoods(foods);
纵观上述过程,发现并没有特殊的地方,除了第3步 点餐这个地方,好像有点意思。
第3步可以大概理解为 按照客户的要求构建产品。该产品十分复杂,一份炸鸡,一份薯条,再加上两个汉堡。
那么假如我要两份炸鸡,一份薯条,三个汉堡,该怎么办?
w.order(FoodType.Chicken).order(FoodType.Chicken).order(FoodType.Chicken).order(FoodType.Chip).order(FoodType.HAMBURGER).order(FoodType.HAMBURGER).order(FoodType.HAMBURGER);
看吧并没有什么难的。只要不断的下订单,不管多少复杂的订单我都照但全收了。
实际上这里隐藏了Builder设计模式,
问题:在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定。
解决方案:
建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
适用性:
在以下情况使用Builder模式
•当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
•当构造过程必须允许被构造的对象有不同的表示时。
结 构:
• 抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
• 具体建造者(ConcreteBuilder)
1)实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。
2)定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建
3) 提供一个检索产品的接口
4) 构造一个使用Builder接口的对象即在指导者的调用下创建产品实例
指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。
产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。
在我们上个例子中:
抽象建造者 ———— Cook 提供接口
public void cook(FoodType type);
然后我们具体建造者 ———— Pantryman 根据订单要求构建产品。
同时提供一个方法,将构建的产品交给服务员Waiter。
public List<Food> getFoods()
而指导者 ———— Waiter 则指导用户如何订餐,然后将订单给我们的配餐员Pantryman
public Waiter order(FoodType type)
这里的产品角色 ———— 其实就是我们按照客户需求所做的各种食物。
private List<Food> foods = new LinkedList<Food>();
不废话了,这里直接贴上所有代码。
enum FoodType {
CHIP, HAMBURGER, CHICKEN
}
abstract class Food {
abstract public String getName();
}
class Chip extends Food {
private String name = "Chip";
public Chip(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
class Hamburger extends Food {
private String name = "Hamburger";
public Hamburger(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
class Chicken extends Food {
private String name = "Chicken";
public Chicken(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
interface KGFFoodLine {
public Food cookChip();
public Food cookHamberger();
public Food cookChicken();
}
class BeijingFoodLine implements KGFFoodLine {
@Override
public Food cookChip() {
return new Chip("Beijing Chip");
}
@Override
public Food cookHamberger() {
return new Hamburger("Beijing Hamberger");
}
@Override
public Food cookChicken() {
return new Chicken("Beijing Chicken");
}
}
class Customer {
private static String[] remarks = { "taste not so bad, i like it.", "damn bad, it smells like expired.",
"yummy,yummy." };
public FoodType makeOrder() {
FoodType[] types = FoodType.values();
int type = (int) (Math.random() * 100) % types.length;
return types[type];
}
public void eatFoods(List<Food> foods) {
for (Food food : foods) {
String remark = remarks[(int) (Math.random() * 100) % remarks.length];
System.out.println(food.getName() + "," + remark);
}
}
}
好的,这里我就要考考你们上一篇设计模式是否有所领悟,这是什么设计模式呢?
Bingo,没错 就是抽象工厂方法设计模式,回忆一下,什么是抽象工厂方法设计模式呢?
就是生产一系列产品族的工厂设计模式。
咱们这里是具体视察的BeijingKFG分店。
这里综合运用上篇的抽象工厂方法设计模式来产生各种食物。
这里是本篇中新加的部分
interface Cook {
public void cook(FoodType type);
}
class Pantryman implements Cook {
private List<Food> foods = new LinkedList<Food>();
private KGFFoodLine foodLine = new BeijingFoodLine();
@Override
public void cook(FoodType type) {
switch (type) {
case CHIP:
foods.add(foodLine.cookChip());
break;
case HAMBURGER:
foods.add(foodLine.cookHamberger());
break;
case CHICKEN:
foods.add(foodLine.cookChicken());
break;
default:
break;
}
}
public List<Food> getFoods() {
List<Food> orders = foods;
foods = new LinkedList<Food>();
return orders;
}
}
class Waiter {
private Pantryman chef = new Pantryman();
public Waiter order(FoodType type) {
chef.cook(type);
return this;
}
public List<Food> getFoods() {
return chef.getFoods();
}
}
public class Builder {
public static void main(String[] args) {
Waiter w = new Waiter();
Customer c = new Customer();
w.order(FoodType.CHICKEN).order(FoodType.CHIP).order(FoodType.HAMBURGER).order(FoodType.HAMBURGER);
List<Food> foods = w.getFoods();
c.eatFoods(foods);
}
}
好了,作为本篇的末尾,
我们需要总结一下使用该种设计带来的好处。
1 ) 它使你可以改变一个产品的内部表示 Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。———— 比如说所有食品的组合,这个地方用LinkedList 其实很容易猜测出来,那么如果下次咱们换到装配一辆汽车呢,谁关心汽车是怎么装配的呢? 我要一个空调,那么就给我装一个空调就好了。
2) 它将构造代码和表示代码分开 Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个Concrete Builder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。———— 这里我们的w 之后再接待多少个客人 都能返回客人所订餐的所有食物,无论订单产生了何种变化,都能准确的完成服务。
3 ) 它使你可对构造过程进行更精细的控制 Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。———— 我们一步一步的根据的客人的意图完成订单的完成。
最后实在抱歉,个人能力不够没有在spring中找到buidler设计模式的代码。