概述
创建者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
与工厂模式相比,创建者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——指挥类(负责流程控制)。
工厂模式:是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;每一次工厂对象被调用时都会返回一个完整的产品对象,而客户端有可能会决定把这些产品组装成一个更大更复杂的产品,也有可能不会
创建者模式:创建者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给指挥类。由指挥类负责将各个组件按照特定的规则组建为产品,组装过程就发生在创建者角色内部,然后将组建好的产品交付给客户端。工厂模式返回不同组成属性,而建造者模式则把它们组装起来
涉及角色
- Builder
抽象创建者角色:对复杂对象的创建过程加以抽象,给出一个抽象接口,以规范产品对象的各个组成部分的建造。引入抽象创建者的目的,是为了将建造的具体过程交与它的子类来实现。这样更容易扩展。 - ConcreteBuilder
具体创建者角色:实现Builder接口,针对不同的业务逻辑,具体化复杂对象的各个部分的创建。在建造过程完成后,提供产品的实例。一般至少会有两个抽象方法,一个用来建造产品(组装产品的多个部分),一个是用来返回产品 - Director
指挥者:调用具体创建者来创建复杂对象的各个部分,在指导者中不设计具体产品的信息,只负责保证对象各部分完整创建或者按某种顺序创建。一般来说,该类被用来封装程序中易变的部分 - 对象:要创建的复杂对象,一般来说包含多个部分。
UML
使用场景
- 创建一些复杂对象时,这些对象的内部组成部分之间的建造顺序是稳定的,但对象的内部组成构建面临着复杂的变化。
- 要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
优点
- 使用创建者模式可以使客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 便于控制细节风险具体的创建者类之间是相互独立的,这有利于系统的扩展,可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 具体的创建者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
代码示例
使用创建者模式有一个隐含的前提,那就是这些产品有共同的特性,也就是说可以用共同的接口实现。另外需要主要的是在Builder中返回的是产品的共同父类,这样才能满足多个产品的返回都正常
比如:一个加工厂包含如下角色:工厂厂长(Director)、员工(ConcreteBuilder)、生产流程规范(Abstractbuilder)、具体生产的产品(Product)
package com.designpattern.builder;
public interface Product {
public void createProductAttributes(String attribute);
public void showAttributes() ;
}
package com.designpattern.builder;
import java.util.ArrayList;
import java.util.List;
public class Pen implements Product {
private List<String> attributes = new ArrayList<String>();
@Override
public void createProductAttributes(String attbute) {
// TODO Auto-generated method stub
attributes.add(attbute);
}
@Override
public void showAttributes() {
// TODO Auto-generated method stub
for (String attribute : attributes) {
System.out.println(attribute);
}
}
}
定义生产流程规范,如起名字、刷颜色、输出产品等……
package com.designpattern.builder;
public interface ProcedureRule {
public void setName();
public void setColor();
public Product getproduct();
}
员工为具体的创建者,需要按产品的生产流程生产产品
package com.designpattern.builder;
public class EmployeeForPen implements ProcedureRule {
private Product product = new Pen();
@Override
public void setName() {
// TODO Auto-generated method stub
product.createProductAttributes("set Name");
}
@Override
public void setColor() {
// TODO Auto-generated method stub
product.createProductAttributes("set Color");
}
@Override
public Product getproduct() {
// TODO Auto-generated method stub
return product;
}
}
package com.designpattern.builder;
public class EmployeeForCup implements ProcedureRule {
private Product product = new Cup();
@Override
public void setName() {
// TODO Auto-generated method stub
product.createProductAttributes("cup set Name");
}
@Override
public void setColor() {
// TODO Auto-generated method stub
product.createProductAttributes("cup set Color");
}
@Override
public Product getproduct() {
// TODO Auto-generated method stub
return product;
}
}
指挥类:主管告诉员工生产产品
package com.designpattern.builder;
public class Master {
private ProcedureRule procedureRule = null;
public Master(ProcedureRule procedureRule) {
// TODO Auto-generated constructor stub
this.procedureRule = procedureRule;
}
public Product build() {
procedureRule.setName();
procedureRule.setColor();
return procedureRule.getproduct();
}
}
客户端:客户与主管洽谈业务,下订单需要钢笔、需要杯子
package com.designpattern.builder;
public class TestMain {
public static void main(String[] args) {
Master master = new Master(new EmployeeForPen());
Product product = master.build();
product.showAttributes();
master = new Master(new EmployeeForCup());
product = master.build();
product.showAttributes();
}
}
另外一个例子:
通常在多属性类中,构造函数有多种组合,此时可能需要写很多构造函数,满足各种属性组合,通常的做法是多个构造函数调用一个统一的构造函数,实在不行就写多个,如
public class Product {
private String name;
private String type;
private String price;
private String color;
private String size;
public Product(String name, String type, String price, String color, String size) {
super();
this.name = name;
this.type = type;
this.price = price;
this.color = color;
this.size = size;
}
public Product(String name, String type, String price, String color) {
new Product(name, type, price, color, "");
}
public Product(String name, String type, String price) {
new Product(name, type, price, "", "");
}
public Product(String name, String type) {
new Product(name, type, "", "", "");
}
public Product(String name) {
new Product(name, "", "", "", "");
}
//省略了其他的组合情况~
}
这种一定程度上省略了一部分代码,代码量还是很多。看如何用创建者模式解决该问题(省略了指挥类)
package com.designpattern.builder2;
public class Product {
private String name;
private String type;
private String price;
private String color;
private String size;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public Product(String name, String type, String price, String color, String size) {
super();
this.name = name;
this.type = type;
this.price = price;
this.color = color;
this.size = size;
}
}
package com.designpattern.builder2;
public class Builder {
private String builder_name;
private String builder_type;
private String builder_price;
private String builder_color;
private String builder_size;
public Builder setName(String name) {
this.builder_name = name;
return this;
}
public Builder setType(String type) {
this.builder_type = type;
return this;
}
public Builder setPrice(String price) {
this.builder_price = price;
return this;
}
public Builder setColor(String color) {
this.builder_color = color;
return this;
}
public Builder setSize(String size) {
this.builder_size = size;
return this;
}
public Product build() {
return new Product(builder_name, builder_type, builder_price, builder_color, builder_size);
}
}
package com.designpattern.builder2;
public class TestMain {
public static void main(String[] args) {
Product product=new Builder().setColor("color").setName("name").build();
System.err.println(product.getColor());
System.err.println(product.getName());
System.err.println(product.getPrice());
}
}
color
name
null
补充上指挥者
package com.designpattern.builder2;
public class Master {
private Builder builder = null;
public Master(Builder builder) {
this.builder = builder;
}
public Product build() {
builder.setColor("Master set color");
builder.setName("Master set name");
return builder.build();
}
}
修改测试主类为
package com.designpattern.builder2;
public class TestMain {
public static void main(String[] args) {
//测试省略指挥类
Product product=new Builder().setColor("color").setName("name").build();
System.err.println(product.getColor());
System.err.println(product.getName());
System.err.println(product.getPrice());
//测试带指挥类
Builder builder = new Builder();
Master master = new Master(builder);
product=master.build();
System.err.println(product.getColor());
System.err.println(product.getName());
System.err.println(product.getPrice());
}
}