目录
-
/ 前言 /
单例模式是为了保证系统内部只有一个对象,工厂模式是为了不重复的创建对象并解除客户端与业务之间的耦合性,那么我们就来看一下建造者模式到底能为我们创造什么价值
-
/ 1 / 为什么要用建造者模式
我们还是拿键盘来举例子,一个键盘的组件有键帽,机械轴,底盘,数据线。不同的客户需要需求也是不一样的,可能有的人喜欢87键,有人喜欢104键,所以我们最好不要直接生产整个键盘,应该是生产不同的组件,然后根据客户的需求去进行拼接,这样我们可以灵活的处理客户的需求。
可能有的朋友会疑问为什么我不用工厂模式来解决这个问题呢,之所以建造者模式所采用的例子也是键盘就是为了帮助大家更好的来理解工厂模式和建造者模式,所以先不要着急,在文末我会解释清楚
-
/ 2 / 建造者模式怎么用
-
我们先来看一下建造者模式的定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
扫描二维码关注公众号,回复: 11218079 查看本文章我们来解释一下这个定义
复杂对象 :键盘
构建与表示分离 :我们将创建的过程抽取出来形成了流程,这个流程不光可以创建雷蛇的键盘啊,还可以
创建其它品牌的键盘,甚至可以定制化制作
-
话不多说,我们直接上代码
我们先来看一下UML类图
创建键盘的抽象类(制作流程),封装了制作键盘的全部工艺流程
/** * @author wise */ public abstract class KeyBoardBuilder { protected BoardProduct product; protected abstract void buildKeyCap(); protected abstract void buildAxle(); protected abstract void buildChassis(); protected abstract void buildDataLine(); protected abstract BoardProduct getProduct(); }
要创建的雷蛇键盘(建造者)
/** * @author wise */ public class RazerBuilder extends KeyBoardBuilder { public RazerBuilder () { super.product = new BoardProduct(); } @Override public void buildKeyCap() { product.setKeyCap("雷蛇键帽"); } @Override public void buildAxle() { product.setAxle("雷蛇机械轴"); } @Override public void buildChassis() { product.setChassis("雷蛇底盘"); } @Override public void buildDataLine() { product.setDataLine("雷蛇数据线"); } @Override public BoardProduct getProduct() { return product; } }
要创建的定制键盘(建造者)
/** * @author wise */ public class CustomizedBuild extends KeyBoardBuilder{ public CustomizedBuild () { super.product = new BoardProduct(); } @Override public void buildKeyCap() { product.setKeyCap("定制键帽"); } @Override public void buildAxle() { product.setAxle("定制机械轴"); } @Override public void buildChassis() { product.setChassis("定制底盘"); } @Override public void buildDataLine() { product.setDataLine("定制数据线"); } @Override public BoardProduct getProduct() { return product; } }
产品类,封装产品的属性
/** * @author wise * @Description 产品类,封装产品的属性 */ @Data public class BoardProduct { private String keyCap; private String axle; private String chassis; private String dataLine; }
在指挥者中根据客户端的选择执行创建流程(客户端和业务解耦)
/** * @author wise * @Description 导演、指挥者(解耦) */ public class Director { public void buildKeyBoard (KeyBoardBuilder builder) { builder.buildAxle(); builder.buildChassis(); builder.buildKeyCap(); builder.buildDataLine(); } }
客户端
public class Client { public static void main(String[] args) { Director director = new Director(); KeyBoardBuilder builder = new RazerBuilder(); director.buildKeyBoard(builder); BoardProduct product = builder.getProduct(); System.out.println("雷蛇键盘 :" + product); builder = new CustomizedBuild(); director.buildKeyBoard(builder); product = builder.getProduct(); System.out.println("定制键盘 :" + product); } }
结果输出
雷蛇键盘 :(keyCap=雷蛇键帽, axle=雷蛇机械轴, chassis=雷蛇底盘, dataLine=雷蛇数据线)
定制键盘 :(keyCap=定制键帽, axle=定制机械轴, chassis=定制底盘, dataLine=定制数据线)
我们来看一下整体流程
客户端(Client)选取具体的产品(雷蛇键盘或者定制键盘)后告诉指挥者(Director),指挥者根据产品信息来调用该产品的生产流程完成生产,然后客户端直接获取产品即可(
builder.getProduct()
)这样我们可以保证只要按照生产流程生产出来的产品是绝对不会缺失部件的,你也不用担心破产了。
-
-
/ 3 / 工厂模式和建造者模式
学会了建造者模式之后可能有的朋友疑问更深了,为啥我不能用工厂模式来解决呢,我把创建的代码抽取到工厂中去,然后根据客户端的选择直接创建产品不就行了吗?
其实单独从代码层面来看的话工厂模式是完全可以替代建造者模式的,但是我们要从其它角度看一下,从代码中应该能感觉到建造者模式更注重的是键盘组装的过程,也就是键盘的定制化生产,一个键盘是由各个部件所组装而成的,部件不同,生产出来的产品自然也就不同,而工厂模式更多注重的是产品,而不是产品的部件,比如在我的博客中你可以看到设计模式(二)- 抽象工厂及演化之路,工厂模式更倾向于怎么高效的生产产品,而不是产品中所需要的组件,二者你可以理解为建造者模式关注的面更深一些,而工厂模式关注的面更广一些
说了这么多那么在具体的应用中我们要怎么选择,如果你在设计系统的时候发现你的产品需要进行定制化(需要频繁的修改产品的内部属性)的生产,那么就可以直接选择建造者模式,如果你更多关注的是产品的生产效率就选择工厂模式
我给大家分享一个我应用过的场景,我需要调用一个3D的算法,这个算法比较复杂,而且适用的场景也比较多,所需参数类别较多,我需要能稳定、灵活的去创建这个参数对象,参数的类别大致可分为3部分,分别是模型参数类别、标识类别、用户指定类别,此时我更多的关注点是在参数类别上面的,我需要明确的区分这些参数类别根据当前使用场景完成实体的定制化初始化,所以我选择的就是建造者模式
-
/ 4 / 结语
建造者模式是创建型模式中比较特别的一个模式,但特别只是你主观上的看法,虽然先学习工厂模式会让我们学习建造者模式更加简单,但是也更加难以做选择,所以我们不妨简单的认为这俩个模式仅仅只是从不同的角度看问题罢了,只要能解决了问题就OK
建造者模式到此结束~
-