建造者模式
前言
本人本科在读大二,准确来说,从大一下开始认认真真学习Java,从面向对象基础到servlet,jsp,并且通过原生JavaWeb项目进入了自己学校的工作室,然后又学习了各大框架,直到springboot,并且利用它做了两个项目,但是我觉得越往后学,感觉自己没有学到很硬核的东西,后面我就有想学习数据结构和设计模式的想法,所以我就打算跟着视频去学一学。前面我已经学了几个设计模式,感觉设计的非常巧妙,所以想在这里记录一下。
定义
The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
其实说实话,看到这个,估计大部分人都不知道是什么意思,稍后我们会慢慢解释的。
实现1.0
在这里,我们举一个例子,我们要去购买电脑,电脑肯定有配置,供我们选择,所以首先实例化一个电脑类
class Computer {
private String cpu;
private String gpu;
private String memory;
private String hd;
}
怕占用空间,我就把get,set和toString方法删去了。
现在我们就需要买电脑了,我们肯定要关心配置,所以就自己去配。
public class AppTest {
public static void main(String[] args) {
Computer c = new Computer();
c.setCpu("i5");
c.setGpu("gt940mx");
c.setMemory("16g");
c.setHd("1T机械");
System.out.println(c);
}
}
但是如果是这样的话,我们会发现一些问题:
1
.客户端程序员,在实例化好产品的对象之后,必须为该对象的每一个属性赋值,这样对于客户端程序员来说,太麻烦了
2
.违反了迪米特法则(即客户端知道的越少越好,尽量已经把电脑配好了)
这相当于你去配电脑,商家把零件全给你,你自己组装电脑!
实现2.0
为了解决这样的问题,我们就新建一个电脑建造类,让这个类来帮我们对属性赋值。
class ComputerBuilder{
Computer c = new Computer();
public Computer builder(){
c.setCpu("i5");
c.setGpu("gt940mx");
c.setMemory("16g");
c.setHd("1T机械");
return c;
}
}
public class AppTest2 {
public static void main(String[] args) {
ComputerBuilder builder = new ComputerBuilder();
Computer c = builder.builder();
System.out.println(c);
}
}
如果这样做的话,确实解决了上述问题,客户端程序员需要一个产品时,直接向建造者要即可,建造者封装了创建电脑的"复杂"过程,我们就不用进行赋值了,但是这样做仍然有一些问题:封装的太狠了,无论客户的需求是什么,都是采用最高配置,这相当于你去配电脑,无论是什么需求,商家都会给你配置最贵的电脑。
实现3.0
为了解决上述问题,我们新建了三个类AdvancedComputerBuilder,MiddleComputerBuilder,LowComputerBuilder,即高端,中端,低端三个类,这样就可以根据客户端的不同需求,使用不同的建造者来生产产品。
class AdvancedComputerBuilder{
Computer c = new Computer();
public Computer builder(){
c.setCpu("i7");
c.setGpu("gt940mx");
c.setMemory("16g");
c.setHd("5T机械");
return c;
}
}
class MiddleComputerBuilder{
Computer c = new Computer();
public Computer builder(){
c.setCpu("i5");
c.setGpu("gt500mx");
c.setMemory("8g");
c.setHd("3T机械");
return c;
}
}
class LowComputerBuilder{
Computer c = new Computer();
public Computer builder(){
c.setCpu("i3");
c.setGpu("gt400mx");
c.setMemory("4g");
c.setHd("1T机械");
return c;
}
}
但是仍然是有问题的:
1
.我们发现,多个不同的建造者中的代码,在重复!代码出现了重复代码就不好了
2
.建造的过程不稳定,如果在某个建造者创建产品的过程中,漏掉了某一步,编译器也不会报错
实现4.0
针对于 3.0的问题,我们使用一个接口来约束电脑建造者,让它必须执行某些步骤,建造者类中的建造过程比较稳定,不会漏掉某一步
interface ComputerBuilder{
void setCpu();
void setGpu();
void setMemory();
void setHd();
Computer builder();
}
让那几个建造者全部实现这个接口,这样的话就可以不会漏掉步骤了
class AdvancedComputerBuilder1 implements ComputerBuilder1{
Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("i7");
}
@Override
public void setGpu() {
computer.setGpu("gt940mx");
}
@Override
public void setMemory() {
computer.setMemory("16g");
}
@Override
public void setHd() {
computer.setHd("5T机械");
}
@Override
public Computer builder() {
return computer;
}
}
class MiddleComputerBuilder1 implements ComputerBuilder1{
Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("i5");
}
@Override
public void setGpu() {
computer.setGpu("gt500mx");
}
@Override
public void setMemory() {
computer.setMemory("8g");
}
@Override
public void setHd() {
computer.setHd("3T机械");
}
@Override
public Computer builder() {
return computer;
}
}
class LowComputerBuilder1 implements ComputerBuilder1{
Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("i3");
}
@Override
public void setGpu() {
computer.setGpu("gt400mx");
}
@Override
public void setMemory() {
computer.setMemory("4g");
}
@Override
public void setHd() {
computer.setHd("1T机械");
}
@Override
public Computer builder() {
return computer;
}
}
public class AppTest4 {
public static void main(String[] args) {
AdvancedComputerBuilder1 acb = new AdvancedComputerBuilder1();
MiddleComputerBuilder1 mcb = new MiddleComputerBuilder1();
LowComputerBuilder1 lcb = new LowComputerBuilder1();
acb.setCpu();
acb.setGpu();
acb.setMemory();
acb.setHd();
Computer c1 = acb.builder();
System.out.println(c1);
}
}
其实看到这里,又会有新的问题出现了:
代码仍然有重复
现在又变成了客户端自己配置电脑,违反了迪米特法则
目前和第一次相比,就是说自己不用自己去动手挑选零件然后组装,现在只需要自己去指挥干什么,干什么。
而最终的建造者模式就是要解决自己去指挥的功能
实现5.0:建造者模式
我们新建一个指挥类
class Director{
public Computer builder(ComputerBuilder1 c){
c.setCpu();
c.setGpu();
c.setHd();
c.setMemory();
return c.builder();
}
}
让这个指挥类来帮助我们去指挥,我们只需要得到最后的电脑就行
public class AppTest5 {
public static void main(String[] args) {
//游戏
AdvancedComputerBuilder acb = new AdvancedComputerBuilder();
//开发
MiddleComputerBuilder mcb = new MiddleComputerBuilder();
//办公
LowComputerBuilder lcb = new LowComputerBuilder();
Director director = new Director();
System.out.println(director.builder(acb));
System.out.println(director.builder(mcb));
System.out.println(director.builder(lcb));
}
}
这样就是最后的建造者模式,其实在客户端我们还可以定义更多的电脑建造者,只需实现电脑建造接口,就可以无缝衔接,得到新的电脑
class MiddleHighComputerBuilder implements ComputerBuilder1{
Computer c = new Computer();
@Override
public void setCpu() {
c.setCpu("i5 8500h");
}
@Override
public void setGpu() {
c.setGpu("dfg");
}
@Override
public void setMemory() {
c.setMemory("wew");
}
@Override
public void setHd() {
c.setHd("rg");
}
@Override
public Computer builder() {
return c;
}
}
public class AppTest5 {
public static void main(String[] args) {
//中等偏上配置电脑
MiddleHighComputerBuilder mhcb = new MiddleHighComputerBuilder();
Director director = new Director();
System.out.println(director.builder(mhcb));
}
}
最终的建造者模式可以自己扩展任意场景的电脑建造者(符合开闭原则),其实对比抽象工厂,工厂模式更侧重于生产,而建造者模式侧重于生产的过程,就行工厂模式讲的汉堡包一样,只是生产汉堡包,而没有去了解汉堡包的原料,建造者就更具侧重于建造的过程。
结语
可能由于自身的水平限制,可能本篇文章有一些问题,还烦请大家谅解,同时希望大家能够有一些建议给我,无论是哪一方面的,谢谢大家!