建造者模式--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、  产品类非常复杂,或者产品类的不同的调用顺序产生不同的结果。

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

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

转载于:https://www.cnblogs.com/littleQin/p/3681839.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值