zoukankan      html  css  js  c++  java
  • 简说设计模式——建造者模式

    一、什么是建造者模式

      我们先说一个生活中的小例子,当我们在外面饭店吃饭时,比如点个水煮肉片,这家店可能会辣一点、那家店可能会咸一点、对面那家可能放青菜、隔壁那家可能放菠菜,每家店做出来的都不一样,明明都是水煮肉片却有不同的做法,如果都一样就不会说这家难吃那家好吃了。那再看快餐店,比如KFC,我们点个至尊虾堡,所有人不管在哪个城市哪家店,做法、味道都是一样的,为什么呢,因为它用料、时间、温度等等都是严格规定的,我们只需要下订单就行了,这就是一个建造者模式。

           建造者模式(Builder),将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。UML结构图如下:

           其中,Director为指挥者/导演类,负责安排已有模块的顺序,然后告诉Builder开始建造;Builder是抽象建造者,规范产品的组建,一般由子类实现;ConcreteBuilder是具体建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象;Product是产品类,通常实现了模板方法模式。

        1. Director类

           导演类起到封装的作用,避免高层模块深入到建造者内部的实现类。在建造者模式比较庞大时,导演类可以有多个。

    1 public class Director {
    2     
    3     public void Construct(Builder builder) {
    4         builder.BuildPartA();
    5         builder.BuildPartB();
    6     }
    7 
    8 }

        2. Builder类

           抽象建造者类,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法getResult()。

    public abstract class Builder {
        
        public abstract void BuildPartA();        //产品的A部件
        public abstract void BuildPartB();        //产品的B部件
        public abstract Product getResult();    //获取产品建造后结果
    
    }

        3. ConcreteBuilder类

           具体建造者类,有几个产品类就有几个具体的建造者,而且这多个产品类具有相同的接口或抽象类。这里给出一个产品类的样例,多个产品类同理。

     1 public class ConcreteBuilder1 extends Builder {
     2 
     3     private Product product = new Product();
     4     
     5     //设置产品零件
     6     @Override
     7     public void BuildPartA() {
     8         product.add("部件A");
     9     }
    10 
    11     @Override
    12     public void BuildPartB() {
    13         product.add("部件B");
    14     }
    15 
    16     //组建一个产品
    17     @Override
    18     public Product getResult() {
    19         return product;
    20     }
    21 
    22 }

        4. Client客户端

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         
     5         Director director = new Director();
     6         Builder builder1 = new ConcreteBuilder1();
     7         Builder builder2 = new ConcreteBuilder2();
     8         
     9         //指挥者用ConcreteBuilder1的方法来建造产品
    10         director.Construct(builder1);
    11         Product product1 = builder1.getResult();
    12         product1.show();
    13         
    14         //指挥者用ConcreteBuilder2的方法来建造产品
    15         director.Construct(builder2);
    16         Product product2 = builder2.getResult();
    17         product2.show();
    18         
    19     }
    20     
    21 }

           运行结果如下:

    二、建造者模式的应用

        1. 何时使用

    • 一个基本部件不会变,而其组合经常变化的时候

        2. 优点

    • 封装性。是客户端不必知道产品内部组成的细节。
    • 建造者独立,易扩展。
    • 便于控制细节风险。可以对建造过程逐步细化,而不对其他模块产生任何影响。

        3. 缺点

    • 产品必须有共同点,范围有限制。
    • 如果内部变化复杂,会有很多建造类。

        4. 使用场景

    • 相同的方法,不同的执行顺序,产生不同的事件结果时。
    • 需要生成的对象具有复杂的内部结构时。
    • 多个部件或零件,都可以装配到一个对象中,但产生的结果又不相同时。

        5. 与工厂模式的区别

    • 建造者模式更关注于零件装配的顺序

        6. 应用实例

    • KFC的食品制作流程,原料多少克、加热几分钟等都有严格的规定,我们只需点餐即可,无论在哪里点的都是一样的。
    • 去KFC吃汉堡、薯条、炸鸡等,这些单品是不变的,其组合是经常改变的,也就是所谓的“套餐”。
    • Java中的StringBuilder/StringBuffer。

    三、建造者模式的实现

           下面我们看一个KFC点套餐的例子,我们点餐可以点一个汉堡和一个冷饮,汉堡可以是鸡肉汉堡、虾堡等等,是装在盒子中的,冷饮可以是可乐、雪碧等等,是装在瓶子中的。下面我们来用建造者模式对其进行组合,用户只需提交订单即可,UML图如下:

        1. Item接口

           创建一个表示食物条目和食物包装的接口。

     1 public interface Item {
     2 
     3     //获取食物名称
     4     public String getName();
     5     //获取包装
     6     public Packing packing();
     7     //获取价格
     8     public float getPrice();
     9     
    10 }
    1 public interface Packing {
    2 
    3     //获取包装类型
    4     public String getPack();
    5     
    6 }

        2. 包装类

           实现Packing接口的实现类。Wapper为纸盒包装,Bottle为瓶装。

    1 public class Wrapper implements Packing {
    2 
    3     @Override
    4     public String getPack() {
    5         return "纸盒";
    6     }
    7 
    8 }
    1 public class Bottle implements Packing {
    2 
    3     @Override
    4     public String getPack() {
    5         return "纸杯";
    6     }
    7 
    8 }

        3. 食品类

           创建实现Item接口的抽象类。Burger为汉堡,Drink为饮品。

     1 public abstract class Burger implements Item {
     2 
     3     @Override
     4     public Packing packing() {
     5         return new Wrapper();
     6     }
     7     
     8     @Override
     9     public abstract float getPrice();
    10     
    11 }
     1 public abstract class Drink implements Item {
     2 
     3     @Override
     4     public Packing packing() {
     5         return new Bottle();
     6     }
     7     
     8     @Override
     9     public abstract float getPrice();
    10     
    11 }

        4. 具体食品类

           创建扩展了Burger和Drink的具体实现类。这里简单的就设为Burger1、Burger2、Drink1、Drink2。各写一个,多余的就不赘述了。

     1 public class Burger1 extends Burger {
     2 
     3     @Override
     4     public String getName() {
     5         return "汉堡1";
     6     }
     7 
     8     @Override
     9     public float getPrice() {
    10         return 25.0f;
    11     }
    12 
    13 }
     1 public class Drink1 extends Drink {
     2 
     3     @Override
     4     public String getName() {
     5         return "饮品1";
     6     }
     7 
     8     @Override
     9     public float getPrice() {
    10         return 15.0f;
    11     }
    12 
    13 }

        5. Meal类

     1 public class Meal {
     2     
     3     private List<Item> items = new ArrayList<>();
     4     
     5     public void addItem(Item item) {
     6         items.add(item);
     7     }
     8     
     9     //获取总消费
    10     public float getCost() {
    11         float cost = 0.0f;
    12         
    13         for (Item item : items) {
    14             cost += item.getPrice();
    15         }
    16         
    17         return cost;
    18     }
    19     
    20     public void showItem() {
    21         for (Item item : items) {
    22             System.out.print("餐品:" + item.getName());
    23             System.out.print(",包装:" + item.packing().getPack());
    24             System.out.println(",价格:¥" + item.getPrice());
    25         }
    26     }
    27 
    28 }

        6. 指挥者

     1 public class MealBuilder {
     2 
     3     //订单1
     4     public Meal order1() {
     5         Meal meal = new Meal();
     6         meal.addItem(new Burger1());
     7         meal.addItem(new Drink1());
     8         
     9         return meal;
    10     }
    11     
    12     //订单2
    13     public Meal order2() {
    14         Meal meal = new Meal();
    15         meal.addItem(new Burger2());
    16         meal.addItem(new Drink2());
    17         
    18         return meal;
    19     }
    20     
    21 }

        7. Client客户端

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         MealBuilder mealBuilder = new MealBuilder();
     5         
     6         //获取第一个订单
     7         Meal order1 = mealBuilder.order1();
     8         System.out.println("------order1------");
     9         order1.showItem();
    10         System.out.println("总额:¥" + order1.getCost());
    11         
    12         //获取第二个订单
    13         Meal order2 = mealBuilder.order2();
    14         System.out.println("------order2------");
    15         order2.showItem();
    16         System.out.println("总额:¥" + order2.getCost());
    17     }
    18     
    19 }

           运行结果如下:

           源码地址:https://gitee.com/adamjiangwh/GoF

  • 相关阅读:
    【Educational Codeforces Round 101 (Rated for Div. 2) C】Building a Fence
    【Codeforces Round #698 (Div. 2) C】Nezzar and Symmetric Array
    【Codeforces Round #696 (Div. 2) D】Cleaning
    【Codeforces Round #696 (Div. 2) C】Array Destruction
    【Educational Codeforces Round 102 D】Program
    【Educational Codeforces Round 102 C】No More Inversions
    【Good Bye 2020 G】Song of the Sirens
    【Good Bye 2020 F】Euclid's nightmare
    使用mobx入门
    requestAnimationFrame 控制速度模拟setinterval
  • 原文地址:https://www.cnblogs.com/adamjwh/p/9033551.html
Copyright © 2011-2022 走看看