建造者模式
Builder Pattern:建造者模式,也可以称为生成器模式,是GoF23种设计模式之中属于创建型模式的一种。主要是提供一个最佳的创建对象的方式。
建造者模式,简单的说就是将创建对象的流程进行了一个抽象;抽象出来的是构建流程,通过这一套流程我们可以构建这个对象的不同的表现形式。
也就是说呢,建造者模式将对象的构建/创建过程和最终的表现形式发生了分离,可以让使用者通过同一套创建过程实现不同的对象表示形式,要是还是不清楚,可以结合下面的例子来看。
结构
结合类图分析一下,建造者模式中有四个角色:
- 被建造的对象:这个角色很好理解,就是最后会被创建出来的对象,而我们最后会使用到的也是这个类的实例对象。
- 抽象建造者:面向接口编程嘛,这里面定义者创建对象需要的流程的各个部分,但是需要注意,这里定义的是流程的各个部分,注意,是各个部分,而不是步骤,不是第一步干什么,第二步干什么,第三步干什么,直接看这个接口,只能知道有这个步骤,有那个步骤,但是这个时候还不知道先哪个后哪个。
- 具体建造者:这就是抽象建造者的具体实现对象了,可以有多个,根据自己的需要来定。
- 指挥者:这个角色呢功能和它的名字是一样的,负责指挥的,指挥什么呢?通过类图可以看到这个指挥者里面有一个建造者的对象,而建造者里面有创建对象的流程的各个部分,那对象如何一步步创造出来呢?这个就需要在指挥者里面定义了,它指挥最后的对象会一步步怎么来创建,也就是流程的实现步骤的定义。
举例
-
编程过程中使用,小编使用最多的就是String类,也就是字符串了,但是当需要创建拼装的字符串的时候,比如说通过几个变量来连接生成最后的字符串,如果直接通过 “+”来进行字符串拼装无疑是浪费内存的做法,这时就会有SpringBuilder类来帮忙了,最后得到的需要的字符串,只需要通过这个类的实例对象将需要拼装的东西一个个的拼装起来就行了,这里用户扮演了指挥者的角色操控着这个StringBuilder建造者,这是因为如何拼装字符串的变化实在是太多,太多,所有指挥者是没有一个统一的流程的,这个不用太在意。
-
生活中的话,小编最近给自己的手机卡换了个套餐,这里的套餐也是使用的是建造者模式哦!
30元/月的套餐,60元/月的套餐,80元/月的套餐,等等等等,里面包含的东西都是一样的,可以发现就是语言通话时间啊,上网流量啊,免费短信啊这些,但是虽然都叫套餐,长的也是一样,可是为什么是不同的价格呢?哎嘿,这里就是同一个对象的不同表达形式了,也许我30元/月的套餐一个月只有1G的流量啊,但是60元/月的套餐可是有着5G的流量呢!
-
还不清楚的话,那么,再举个贴近生活的例子,简简单单的的一份蛋炒饭,相信大家都可以去上手炒出来,但是,额,最后的结果嘛,呵呵呵,都自己心里有点数
有的好吃,有的还行,有的普普通通,有的难吃,不是淡了就是咸了酸了或者辣了,但是,但是,但是,都是蛋炒饭啊?里面也就是蛋加饭啊?当然还加了点其他的调料。
这里呢,蛋炒饭就是被建造的对象,你看书啊,被爸妈教啊,看视频学着做啊就是建造者对象,你自己呢,那就是指挥者对象了,这也是建造者模式的体现哦。
注意
- 好处就是创建和表现分离,扩展性很强,对于一些细节性的过程也可以好好的控制起来,不会让人一不小心,炒蛋炒饭不加蛋的意外情况出现。
- 但是,也有不好的地方就是建造者模式是为一个对象服务的,虽然你可以建造出乱七八糟,然人眼花缭乱的最后呈现出来的对象,而,这个对象除去特性,剩下的还是那个最初的对象而已,也就是说这个范围有着局限性。
一个小DEMO
-
场景
来个小demo场景,嗯,那就以玩游戏来距离吧,比如说一些火热的RPG类型的游戏吧,角色扮演类的游戏嘛,既然是角色扮演,首先你的需要去选择你自己的角色是吧?是要刺客呢?剑客呢?法师呢?枪手呢?或者其他都是可以的啊,只需要点击一个类型的人物,当当当当,你的角色就被创建好了,只需要命名就可以去地图里面遨游了(当然了,现在的大多数游戏都是提供直接手工制作,自己捏模型的啦,这里去繁化简一下呀)
-
定义角色人物,也就是需要被创建出来的最终的对象啦。
package com.builder; /** * 建造者模式——需要被创建的最后的结果对象 * 在这个例子中,也就是角色了 * @author WQ */ public class Role { // 有个头 private String head; // 来个体型 private String body; // 双手 private String hand; // 双脚 private String foot; // getter/setter方法省略,不然占篇幅 @Override public String toString() { return "角色创建完成 [头是这样的-->" + head + ", 身子是这样-->" + body + ", 双手是这样的-->" + hand + ", 双脚是这样的-->" + foot + "]"; } }
-
定义好我们的抽象建造者
package com.builder; /** * 建造者模式——这是抽象建造者 * @author WQ */ public interface Builder { // 只是定义创建的各个部分 void createHead(); void createBody(); void createHand(); void createFoot(); // 得到最终的结果对象 Role getRoel(); }
-
具体的建造者对象,也就是角色的不同表现形式
package com.builder; /** * 建造者模式——具体的建造者 * 嗯,来个刺客 * @author WQ */ public class Assassin implements Builder{ // 具体的建造者,最后肯定是需要将这个对象建造出来的撒 Role role = new Role(); @Override public void createHead() { role.setHead("黑色面罩"); } @Override public void createBody() { role.setBody("小巧玲珑,身穿夜行衣"); } @Override public void createHand() { role.setHand("白皙柔软"); } @Override public void createFoot() { role.setFoot("修长"); } @Override public Role getRoel() { return role; } } //------------------------------------------ package com.builder; /** * 建造者模式——具体的建造者 * 法师 * @author WQ */ public class Sorcerer implements Builder{ Role role = new Role(); @Override public void createHead() { role.setHead("戴着魔法帽子"); } @Override public void createBody() { role.setBody("宽大的法师袍"); } @Override public void createHand() { role.setHand("白皙柔软"); } @Override public void createFoot() { role.setFoot("修长"); } @Override public Role getRoel() { return role; } } //--------------------------------------------------- package com.builder; /** * 建造者模式——具体的建造者 * 剑客 * @author WQ */ public class Swordsman implements Builder{ Role role = new Role(); @Override public void createHead() { role.setHead("束发垂髫"); } @Override public void createBody() { role.setBody("修身剑客服"); } @Override public void createHand() { role.setHand("强壮有力"); } @Override public void createFoot() { role.setFoot("修长"); } @Override public Role getRoel() { return role; } }
-
指挥者,指挥中心上线
package com.builder; /** * 建造者模式——指挥者 * 剑客 * @author WQ */ public class Conductor { // 需要控制的是建造者 private Builder builder; public Conductor(Builder builder) { this.builder = builder; } // 最后需要完成对象的创建步骤,并且将这个对象生成返回 public Role construct() { // 首先画个头 builder.createHead(); // 然后画身子 builder.createBody(); // 加上双手 builder.createHand(); // 添上双脚 builder.createFoot(); // 创建完成,返回 return builder.getRoel(); } }
-
来个测试类
package com.builder; /** * 建造者模式——测试类 * @author WQ */ public class Main { public static void main(String[] args) { // 呼叫指挥中心,我要个刺客 Role assassin = new Conductor(new Assassin()).construct(); System.out.println(assassin.toString()); // 呼叫指挥中心,我要魔法师 Role sorcerer = new Conductor(new Sorcerer()).construct(); System.out.println(sorcerer.toString()); // 再来个剑客 Role swordsman = new Conductor(new Swordsman()).construct(); System.out.println(swordsman.toString()); } }
-
测试走一波
角色创建完成 [头是这样的-->黑色面罩, 身子是这样-->小巧玲珑,身穿夜行衣, 双手是这样的-->白皙柔软, 双脚是这样的-->修长] 角色创建完成 [头是这样的-->戴着魔法帽子, 身子是这样-->宽大的法师袍, 双手是这样的-->白皙柔软, 双脚是这样的-->修长] 角色创建完成 [头是这样的-->束发垂髫, 身子是这样-->修身剑客服, 双手是这样的-->强壮有力, 双脚是这样的-->修长]
完成!!!