java构造者模式_Java设计模式之-建造者模式(Builder)

关于建造者模式(或者又叫构造者模式),我在网上看了很多文章。其中不乏很多人直接把建造者模式等同于builder构造器。我想说这是两种完全不同的层次和方向,一种是从系统设计层面考虑的设计模式,用于使整个系统构件间解耦更加明显,更易于扩展;另一种则是为了让构造器能适应多个参数而出现的构造函数变体。

这里不再对网上漫天的Builder构造器进行解释,只针对建造者模式进行讨论。

建造者模式:将类的使用者与类的建造方式解耦,将类的使用者与类的建造者解耦。

当然,上面这句话也是我个人对建造者模式的理解。建造者模式就是实现了三点之间的解耦:类的使用者、类的建造者、类的建造方式。

我们先来看一下建造者模式的示意类图:

dd9c9c0f55bc?utm_source=oschina-app

建造者模式

Builder, 抽象建造者,定义了建造一个类(Product)需要实现的方法;

ConcreteBuilder,具体建造者,实现了抽象建造者定义的方法;

Product,产品,其实就是建造者需要建造的东西;

Director,其实它才是真正的类的建造者,上面所说的Builder,其实只是定义了类的建造方式,但是真正和类的使用者交互的是Director,它作为具体类的提供者,完成了建造的步骤。

OK, 我们现在来从上面说的两个解耦进行后续的解释。

将类的使用者与类的建造方式解耦

平常我们想进行一个类的构造会怎么写?一般来说我们先new一个实例出来,然后对各个变量进行set,最后做我们想做的事情。这里大家也可以换成直接在构造函数里面传入参数,大致意思是一样的。

Foo foo = new Foo();

foo.setA(123);

foo.setB("abc");

foo.setC(new bar());

foo.doSomething();

但是这种做法,实际上将类的初始化和各项配置工作都移交给了类的使用者来做,大大增强了类的使用者和类的建造方式之间的耦合关系,类的使用者必须完全了解如何建造这个类才可以,否则便等不到一个功能完好的实例,更不要说正确地使用了。

OK,那如果说我现在有这样一个产品类,会被别人使用到。我们先假设产品类是这个样子:

public class Product {

private String name;

private BigDecimal price;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public BigDecimal getPrice() {

return price;

}

public void setPrice(BigDecimal price) {

this.price = price;

}

}

而我们存在多种建造这个产品的方式,但首先我们需要定义一个接口,用以确定产品的建造者需要做哪些工作:

public interface IProductBuilder {

public void giveName();

public void givePrice();

public Product build();

}

而后我们有了两个建造商品的类,一个生产高质量商品,另一个生产普通商品:

public class HighQualityProductBuilder implements IProductBuilder{

private Product product = new Product();;

@Override

public void giveName() {

product.setName("A High Quality Product comes out!");

}

@Override

public void givePrice() {

product.setPrice(new BigDecimal("299.99"));

}

@Override

public Product build() {

giveName();

givePrice();

refine();

return product;

}

private void refine(){

System.out.println("Don't know how, but the product get refined!");

}

}

public class NormalProductBuilder implements IProductBuilder {

private Product product = new Product();;

@Override

public void giveName() {

product.setName("Product with normal quality......");

}

@Override

public void givePrice() {

product.setPrice(new BigDecimal("1.59"));

}

@Override

public Product build() {

giveName();

givePrice();

return product;

}

}

这个时候我们能够看到,在Builder类中,我已经将值赋给了product的域,并且在build()方法中实现了产品的装配和建造过程。后面会提到,这其实是建造者模式的一大问题所在。

而后,我们在main方法中模拟使用该类,这样其实就能够实现了将类的使用者与类的建造方式解耦这一目的:

public static void main(String[] args){

IProductBuilder builder = new HighQualityProductBuilder();

Product product = builder.build();

}

但是到此为止,我们做得还不够。大家可以看到,在类图中展示的Builder、ConcreteBuilder、和Product都已经出现了,但是Director还迟迟不肯露面。下面我们就来说一下Director在整个建造者模式中的作用。

将类的使用者与类的建造者解耦

为了实现这一解耦目标,我们引入了Director这个参与者。它主要做的工作,就是封装了Builder,然后直接和外界类的使用者进行交互:

public class Director {

private IProductBuilder builder;

public Director(IProductBuilder builder){

this.builder = builder;

}

public Product construct(){

return builder.build();

}

}

而后我们在main方法中使用director来替代原来直接写builder的方式:

public static void main(String[] args){

Director director = new Director(new NormalProductBuilder());

Product product = director.construct();

}

看到这里,很多人可能会骂我根本就不懂。这不还是写死了NormalProductBuilder了么?不照样是紧耦合了么?有什么意义?其实如果大家写过一点Spring就能顿悟这里面的妙处,只要我在Director构造时使用注入,并将其实现为一个Bean,就可以很轻松地将其进行解耦。由一个Director来作为选择和管理Builder的入口,而通过注入的方式将使用者与后方隔离开来,这才是建造者模式真正强大的地方。

一大问题

另外我上面也说了,建造者模式的一大问题,就是它把类的建造过程写死了,绑死了,写成了一套流程化的代码逻辑,不易更改。

所以说,建造者模式适用于不易变更的且构建复杂的类的实例化场景,而对那些生成过程经常改变的类,则不建议使用该模式,因为得到的收益可能远比不上修改的成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值