zoukankan      html  css  js  c++  java
  • 建造者模式--Builder

      模拟场景:在上次的模板设计中,我们根据不同的需求建立有不同特性的car,现在一辆car有什么特性都是由我们内部自己决定的,但是现在有新的要求:所有car的特性都由客户自己决定。比如现在要求要建立BMV,但是BMW也有不同的型号,假如型号A要求只需要start和stop方法,型号B要求start、stop、alarm,型号C先start、engineBoom、stop,型号D。。。怎么根据这些不同的需求来建立重用性高的代码?

      分析:现在既然有不同需求,而且有顺序的要求了,那么就不可以像之前在CarModel中写死了顺序,这样达不到我们的要求。既然有顺序,那么我们可以在CarModel中实例化一个List<String>容器,主要用来装特性执行的顺序,在run方法中循环取出,进行迭代判断,先匹配的先进行执行,不匹配的不执行。

    CarModel

     1 package com.zqz.dp.builder;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 /**
     5  * @author Qin 生产car的模型,所有的才都按照此模板进行设计
     6  */
     7 public abstract class CarModel {
     8          /**
     9           * 定义一个list<String>容器,用来装car跑动时候是否执行,执行的顺序。
    10           * 封装好,提供getter、setter
    11           */
    12          private List<String> orders=new ArrayList<String>();
    13          protected List<String> getOrders() {
    14                    return orders;
    15          }
    16          protected void setOrders(List<String> orders) {
    17                    this.orders = orders;
    18          }
    19          /**
    20           * 首先car要可以启动起来
    21           */
    22          protected abstract void start();
    23          /**
    24           * 除了可以开动,car也要可以停止下来
    25           */
    26          protected abstract void stop();
    27          /**
    28           * car还要可以鸣笛
    29           */
    30          public abstract void alarm();
    31          /**
    32           * car还要有引擎
    33           */
    34          protected abstract void engineBoom();
    35          /**
    36           * 定义完规定之后,car要开始进行建立模型,下面就是进行具体的操作。设置为final是为了防止子类破坏进行覆写
    37           */
    38          protected final void run() {
    39                    for(String order:orders){        //forEach循环,取出每一个order
    40                             if(order!=null){        //值不为空
    41                                      if(order.equalsIgnoreCase("start")){     //如果start匹配成功
    42                                                this.start(); // car开始启动
    43                                      }else if(order.equalsIgnoreCase("engine boom")){      //如果engineBoom匹配成功
    44                                                this.engineBoom(); // 引擎启动
    45                                      }else if(order.equalsIgnoreCase("alarm")){  //如果alarm匹配成功
    46                                                this.alarm(); // 开始鸣笛
    47                                      }else if(order.equalsIgnoreCase("stop")){    //如果shop匹配成功
    48                                                this.stop(); // car停下来
    49                                      }
    50                             }
    51                    }
    52          }
    53 }

      这样顺序的问题已经解决了,如果想要测试的话,可以在client端建立一个list容器,装上car的需要的特性与顺序,然后通过setter方法设置到自己的car中就可以了。

    修改的Client

     1 package com.zqz.dp.builder.model;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 /**
     5  * @author Qin
     6  * 场景类,主要是按照模板CarModel生成不同的car,并开动起来
     7  */
     8 public class Client {
     9          public static void main(String[] args) {
    10                    System.out.println("-----------建立第一辆car-------------");
    11                    CarModel car1=new Car1();    //根据模板建立第一辆car1
    12                    List<String> orders=new ArrayList<String>();       //建立一个容器来装执行的特性及顺序
    13                    orders.add("start");       //有start的方法
    14                    orders.add("stop");                 //有stop的方法
    15                    car1.setOrders(orders); //设置到car1中
    16                    car1.run();        //开始建立car,让car跑动起来
    17          }
    18 }

      这样确实可以解决问题了,但是否会发现,main方法中的代码太多了,而且如果现在要求有好几种不同型号的car,是否在main方法中要建立多个这样的list容器呢?这样明确是不符合的。所以这个时候用面向对象的知识,就要把这个list容器的全部操作抽象出来,成为独立的一个类。

      在这里,因为是car的建造模型,所以把这个类抽象为CarBuilder,表示用来创建不同的模型的car,那么很明显,这个car肯定有一个setOrders(List<String>),这个方法是用来设置模型的特性及特性的顺序的,当我们建立好模型之后,肯定car就算建立好了,所以在CarBuilder中也应该有一个方法getCarMedol(),表示得到car的模板,当然设置什么模型,得到什么样模板,都是交给子类去实现,所以全部可以定义为abstract。在这里有人会觉得矛盾说,直接把setOrders(List<String>)放在CarModel不是也一样可以实现吗?其实是可以的,不过这样的话CarModel即负责car的特性又关系car的各种特性的执行顺序,兼顾的职责太多了。根据单一职责原则,这里还是构建出一个CarBuilder类会好点,该类只负责CarModel中car的有什么特性且特性的执行顺序。

      认真的读者应该会发现,这里面虽然抽象出来了一个CarBuilder类,但是在main方法中还是存在着大量的代码。car的定制规则都写在main方法中,这样如果我有几百种建造模型的话,是否在main方法中会存在一大堆代码呢?当然你也可以定义成静态的方法来调用,但是这样的操作还不是很符合逻辑的。

      最好的方法时再抽象出一个Director类,此类的意思是导演类,用来控制生成car的不同的模型,在这里生成了BMWCar的A、B型号,BenzCar的A型号。其实如果型号不多的话,可以把Director设计成一个单例设计模式的,但是在这里考虑到拓展,如果类型太多的话,可以衍生出一些子类,如BMWDirector等等。紧接着Client也要进行修改,会发现在main方法中变得非常的简洁。

    修改的CarModel

     1 package com.zqz.dp.builder.model;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 /**
     5  * @author Qin
     6  * 生产car的模型,所有的才都按照此模板进行设计
     7  */
     8 public abstract class CarModel {
     9          /**
    10           * 定义一个list<String>容器,用来装car跑动时候是否执行,执行的顺序。
    11           * 封装好,提供getter、setter
    12           */
    13          private List<String> orders=new ArrayList<String>();
    14          public List<String> getOrders() {
    15                    return orders;
    16          }
    17          public void setOrders(List<String> orders) {
    18                    this.orders = orders;
    19          }
    20          /**
    21           * 首先car要可以启动起来
    22           */
    23          protected abstract void start();
    24          /**
    25           * 除了可以开动,car也要可以停止下来
    26           */
    27          protected abstract void stop();
    28          /**
    29           * car还要可以鸣笛
    30           */
    31          public abstract void alarm();
    32          /**
    33           * car还要有引擎
    34           */
    35          protected abstract void engineBoom();
    36          /**
    37           * 定义完规定之后,car要开始进行建立模型,下面就是进行具体的操作。设置为final是为了防止子类破坏进行覆写
    38           */
    39          public final void run() {
    40                    for(String order:orders){        //forEach循环,取出每一个order
    41                             if(order!=null){        //值不为空
    42                                      if(order.equalsIgnoreCase("start")){     //如果start匹配成功
    43                                                this.start(); // car开始启动
    44                                      }else if(order.equalsIgnoreCase("engine boom")){      //如果engineBoom匹配成功
    45                                                this.engineBoom(); // 引擎启动
    46                                      }else if(order.equalsIgnoreCase("alarm")){  //如果alarm匹配成功
    47                                                this.alarm(); // 开始鸣笛
    48                                      }else if(order.equalsIgnoreCase("stop")){    //如果shop匹配成功
    49                                                this.stop(); // car停下来
    50                                      }
    51                             }
    52                    }
    53          }
    54 }

    BMWCar

     1 package com.zqz.dp.builder.car;
     2 import com.zqz.dp.builder.model.CarModel;
     3 /**
     4  * @author Qin
     5  * 第一辆按照CarModel建立的car1
     6  */
     7 public class BMWCar extends CarModel {
     8          @Override
     9          public void start() {
    10                    System.out.println("bmw启动");
    11          }
    12          @Override
    13          public void stop() {
    14                    System.out.println("bmw停下来");
    15          }
    16          @Override
    17          public void alarm() {
    18                    System.out.println("bmw鸣笛");
    19          }
    20          @Override
    21          public void engineBoom() {
    22                    System.out.println("bmw启动引擎");
    23          }
    24 }
     1 package com.zqz.dp.builder.car;
     2 import com.zqz.dp.builder.model.CarModel;
     3 /**
     4  * @author Qin
     5  * 第一辆按照CarModel建立的car1
     6  */
     7 public class BMWCar extends CarModel {
     8          @Override
     9          public void start() {
    10                    System.out.println("bmw启动");
    11          }
    12          @Override
    13          public void stop() {
    14                    System.out.println("bmw停下来");
    15          }
    16          @Override
    17          public void alarm() {
    18                    System.out.println("bmw鸣笛");
    19          }
    20          @Override
    21          public void engineBoom() {
    22                    System.out.println("bmw启动引擎");
    23          }
    24 }

    BenzCar

     1 package com.zqz.dp.builder.car;
     2 import com.zqz.dp.builder.model.CarModel;
     3 /**
     4  * @author Qin 第二辆按照CarModel建立的car2
     5  */
     6 public class BenzCar extends CarModel {
     7          @Override
     8          public void start() {
     9                    System.out.println("benz启动");
    10          }
    11          @Override
    12          public void stop() {
    13                    System.out.println("benz停下来");
    14          }
    15          @Override
    16          public void alarm() {
    17                    System.out.println("benz鸣笛");
    18          }
    19          @Override
    20          public void engineBoom() {
    21                    System.out.println("benz启动引擎");
    22          }
    23 }

    CarBuilder

     1 package com.zqz.dp.builder.builder;
     2 import java.util.List;
     3 import com.zqz.dp.builder.modelbuilder.CarModel;
     4 /**
     5  * @author Qin
     6  * car的模型,即创建的特性与顺序
     7  */
     8 public abstract class CarBuilder {
     9          /**
    10           * car的模型,存放car的特性,根据不同的顺序是先不同的操作。
    11           * @param orders  :car的特性
    12           * 抽象类,交给子类实现
    13           */
    14          public abstract void setOrders(List<String> orders);
    15          /**
    16           * 得到建立car的model
    17           * @return      carModel,具体是什么样的model交给子类
    18           */
    19          public abstract CarModel getCarModel();
    20 }

    BMWBuilder

     1 package com.zqz.dp.builder.builder;
     2 import java.util.List;
     3 import com.zqz.dp.builder.car.BMWCar;
     4 import com.zqz.dp.builder.model.CarModel;
     5 /**
     6  * @author Qin
     7  * bmwCar的建造器,设置好关系
     8  */
     9 public class BMWBuilder extends CarBuilder {
    10          private CarModel bmwCar=new BMWCar(); //父类实例指向子类,创建BMWCar模型
    11          @Override
    12          public void setOrders(List<String> orders) {
    13                    this.bmwCar.setOrders(orders);   //把存放特性的list集合设置到BMWCar
    14          }
    15          @Override
    16          public CarModel getCarModel() {
    17                    return this.bmwCar;       //取得CarModel,即取得car的建立的模型,这里的实例是BMW的模型
    18          }
    19 }

    BenzBuilder

     1 package com.zqz.dp.builder.builder;
     2 import java.util.List;
     3 import com.zqz.dp.builder.car.BenzCar;
     4 import com.zqz.dp.builder.model.CarModel;
     5 /**
     6  * @author Qin
     7  * benzCar的建造器,设置好关系
     8  */
     9 public class BenzBuilder extends CarBuilder {
    10          private CarModel benzCar=new BenzCar();//父类实例指向子类,创建BenzCar模型
    11          @Override
    12          public void setOrders(List<String> orders) {
    13                    this.benzCar.setOrders(orders);   //把存放特性的list集合设置到BenzCar
    14          }
    15          @Override
    16          public CarModel getCarModel() {
    17                    return this.benzCar;       //取得CarModel,即取得car的建立的模型,这里的实例是Benz的模型
    18          }
    19 }

    Director

     1 package com.zqz.dp.builder.director;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 import com.zqz.dp.builder.builder.BMWBuilder;
     5 import com.zqz.dp.builder.builder.BenzBuilder;
     6 import com.zqz.dp.builder.builder.CarBuilder;
     7 import com.zqz.dp.builder.model.CarModel;
     8 /**
     9  * @author Qin
    10  * 导演类,主要就是用来创建不同的car的建立模型的
    11  * 比如BMWCar有3中类型,即有3中builder
    12  */
    13 public class Director {
    14          /**
    15           * list容器,用来存放car的特性及顺序
    16           */
    17          private List<String> orders=new ArrayList<String>();
    18          /**
    19           * BMWCar的建造模型,即建造器
    20           */
    21          private CarBuilder bmwBuilder=new BMWBuilder();
    22          /**
    23           * BenzCar的建造模型,即建造器
    24           */
    25          private CarBuilder benzBuilder=new BenzBuilder();
    26          /**
    27           * 第一辆bmwCar的建造模型,设置好特性和顺序
    28           * @return      CarModel模板,主要返回的是具体的car
    29           */
    30          public CarModel getABMWCar(){
    31                    this.orders.clear(); //先清空list集合
    32                    this.orders.add("start");        //先启动
    33                    this.orders.add("engine boom"); //启动引擎
    34                    this.orders.add("stop");        //停止
    35                    this.bmwBuilder.setOrders(orders);     //设置list容器到建造器中
    36                    return this.bmwBuilder.getCarModel();        //通过建造器取得对应的car实例
    37          }
    38          /**
    39           * 第二辆bmwCar的建造模型,设置好特性和顺序
    40           * @return      CarModel模板,主要返回的是具体的car
    41           */
    42          public CarModel getBBMWCar(){
    43                    this.orders.clear(); //先清空list集合
    44                    this.orders.add("start");        //先启动
    45                    this.orders.add("alarm");      //鸣笛
    46                    this.orders.add("stop");        //停止
    47                    this.bmwBuilder.setOrders(orders);     //设置list容器到建造器中
    48                    return this.bmwBuilder.getCarModel();        //通过建造器取得对应的car实例
    49          }
    50          /**
    51           * 第一辆benzCar的建造模型,设置好特性和顺序
    52           * @return      CarModel模板,主要返回的是具体的car
    53           */
    54          public CarModel getABenzCar(){
    55                    this.orders.clear(); //先清空list集合
    56                    this.orders.add("start");        //先启动
    57                    this.orders.add("stop");        //停止
    58                    this.benzBuilder.setOrders(orders);     //设置list容器到建造器中
    59                    return this.benzBuilder.getCarModel();        //通过建造器取得对应的car实例
    60          }
    61 }

    Client

     1 package com.zqz.dp.builder.client;
     2 import com.zqz.dp.builder.director.Director;
     3 /**
     4  * @author Qin
     5  * 场景类,主要是按照模板CarModel生成不同的car,并开动起来
     6  */
     7 public class Client {
     8          public static void main(String[] args) {
     9                    Director dir=new Director();   //导演类,决定car的特性及顺序
    10                    System.out.println("-----------建立第一辆car-------------");
    11                    dir.getABMWCar().run();        //通过模板A建立第一辆bmwCar,并让car跑一会
    12                    System.out.println("-----------建立第二辆car-------------");
    13                    dir.getABenzCar().run();//通过模板A建立第一辆benzCar,并让car跑一会
    14          }
    15 }

    在建造者设计模式中,有如下四个角色:

      1、  Product产品类,如上面的BMWCar和BenzCar。考虑到拓展性还有CarModel

      2、  Builder抽象建造者,如CarBuilder

      3、  Builder的实现类,如BMWBuilder、BenzBuilder

      4、  Director导演类,负责告诉Builder如果进行建造

    建造者的优点:

      1、  封装性:客户端Client不需要知道产品类BMWCar和BenzCar的细节,不需要知道建造器Builder是如何实现的,只知道Director中有方法可以调用放回基本CarModel。

      2、  建造者独立,容易扩展:BMWBuilder、BenzBuilder是相互独立的,便于拓展。

      3、  便于控制细节:在拓展中不对其他模块产生影响。

    建造者的使用场景:

      1、  相同的方法,不同的执行顺序,产生不同的事件结果。

      2、  多个部件或者零件,都可以装配到一个对象中,但产生运行的结果又不一样上面的CarModel。

      3、  产品类非常复杂,或者产品类的不同的调用顺序产生不同的结果。

    注意事项:和工厂方法的区别:

      建造者关注的是零件类型跟执行的顺序。记住一点:建造者模式最主要的功能是基本方法的调用顺序,也就是其实基本方法已经实现了。而工厂中最主要的就是创建方法。

  • 相关阅读:
    delphi res 字符串资源
    delphi label1 文字在窗体上水平来回移动
    delphi Edit
    delphi CoolBar这个怎么弄没了
    delphi Components[i]清除所有edit控件中的内容
    delphi Caption 垂直显示标签文本
    delphi array应用 DayOfWeek星期几判断
    delphi 2010 资源文件使用
    delphi 18 屏蔽和替换 右键菜单
    delphi 16 网页缩放
  • 原文地址:https://www.cnblogs.com/littleQin/p/3681839.html
Copyright © 2011-2022 走看看