建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
1、适用场景:
隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
多个部件都可以装配到一个对象中,但产生的运行结果不相同
产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
初始化一个对象时,参数过多,或者很多参数具有默认值
Builder模式不适合创建差异性很大的产品类
产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
2、UML
这里要创建一批不同的产品,指挥者只需要指挥不同的建造者即可,不要要去考虑内部的具体实现,若是以后要新加类似的产品,也只需要新加一个建造者实现建造者接口即可。不影响原来的产品的创建。
3、例子
这里举的例子是要创建两种不同的数据库,Oracle和MySQL,用建造者模式来创建。
4、Product产品类为DB
/**
* 具体的产品。这里是数据库
* @author suibibk.com
*/
public class DB {
private String name="";
private String desc="";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "DB [name=" + name + ", desc=" + desc + "]";
}
}
5、建造者接口Builder
/**
* 抽象的建造者类,要建造这些产品所需要的步骤
* @author suibibk.com
*
*/
public interface Builder {
//建造名称
public void buildName();
//建造描述
public void buildDesc();
//创建产品
public DB createDB();
}
6、具体的建造者OracleBuilder和MySQLBuilder
/**
* 具体的建造者类:Oracle数据库
* @author suibibk.com
*
*/
public class OracleBuilder implements Builder{
private DB db= new DB();
@Override
public void buildName() {
db.setName("创建一个Oracle数据库");
}
@Override
public void buildDesc() {
db.setDesc("Oracle数据库用于作为企业级的数据存储中心使用");
}
@Override
public DB createDB() {
return db;
}
}
/**
* 具体的建造者类:MySQL数据库
* @author suibibk.com
*
*/
public class MySQLBuilder implements Builder{
private DB db= new DB();
@Override
public void buildName() {
db.setName("创建一个MySQL数据库");
}
@Override
public void buildDesc() {
db.setDesc("MySQL数据库用于作为一个免费的的数据存储中心使用");
}
@Override
public DB createDB() {
return db;
}
}
7、指挥者Direct
public class Direct {
private Builder builder;
public Direct(Builder builder) {
this.builder= builder;
}
/**
* 创建产品
* @return
*/
public DB construct() {
builder.buildName();
builder.buildDesc();
DB db = builder.createDB();
return db;
}
}
有指挥者来根据具体需求来创建不同的产品
8、测试Test
public class Test {
public static void main(String[] args) {
Direct d1 = new Direct(new OracleBuilder());
Direct d2 = new Direct(new MySQLBuilder());
DB db1 = d1.construct();
DB db2 = d2.construct();
System.out.println(db1);
System.out.println(db2);
}
}
这里是根据需求来创建不同的产品。运行会输出如下结果:
DB [name=创建一个Oracle数据库, desc=Oracle数据库用于作为企业级的数据存储中心使用]
DB [name=创建一个MySQL数据库, desc=MySQL数据库用于作为一个免费的的数据存储中心使用]
9、优点、缺点
1、优点
使用建造者模式可以使客户端不必知道产品内部组成的细节。
具体的建造者类之间是相互独立的,这有利于系统的扩展。
具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
2、缺点
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
10、建造者模式与抽象工厂模式的比较:
与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族 。
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
总结
建造者模式的使用场合是当创建复杂对象时,把创建对象成员和装配方法分离出来,放在建造者类中去实现,用户使用该复杂对象时,不用理会它的创建和装配过程,只关心它的表示形式。