创建型模式之--创建者模式
Posted ~无关风月~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型模式之--创建者模式相关的知识,希望对你有一定的参考价值。
1、变化是永恒的
制作奔驰、宝马的车辆模型,汽车的启动、停止、喇叭声音、引擎声音 先后顺序由客户控制。
每个车都是一个产品。
在CarModel中我们定义了一个setSequence方法, 车辆模型的这几个动作要如何排布, 是在这个ArrayList中定义的。 然后run()方法根据sequence定义的顺序完成指定的顺序动作。
车辆模型抽象类
public abstract class CarModel {
/**
* 汽车启动顺序
*/
private List<String> sequence = new ArrayList<>();
/**
* 汽车启动
*/
protected abstract void start() ;
/**
* 汽车停止
*/
protected abstract void stop();
/**
* 汽车响铃
*/
protected abstract void alarm();
/**
* 汽车引擎响
*/
protected abstract void engineBoom();
/**
* 汽车启动
*/
final public void run() {
for (String funcName : this.sequence) {
if (funcName.equalsIgnoreCase("start")) {
this.start();
} else if (funcName.equalsIgnoreCase("stop")) {
this.stop();
} else if (funcName.equalsIgnoreCase("alarm")) {
this.alarm();
} else if (funcName.equalsIgnoreCase("enginBoom")) {
this.engineBoom();
}
}
}
/**
* 设置启动顺序
* @param sequence
*/
public void setSequence(List<String> sequence) {
this.sequence = sequence;
}
}
奔驰模型
public class BenzModel extends CarModel{
/**
* 汽车启动
*/
@Override
protected void start() {
System.out.println("奔驰车开跑");
}
/**
* 汽车停止
*/
@Override
protected void stop() {
System.out.println("奔驰车停车");
}
/**
* 汽车响铃
*/
@Override
protected void alarm() {
System.out.println("奔驰车响喇叭");
}
/**
* 汽车引擎响
*/
@Override
protected void engineBoom() {
System.out.println("奔驰车引擎声");
}
}
抽象汽车组装者
public abstract class CarBuilder {
/**
* 设置顺序
* @param sequence
*/
public abstract void setSequence(List<String> sequence);
/**
* 得到模型
* @return
*/
public abstract CarModel getCarModel();
}
奔驰车组装者
public class BMWBuilder extends CarBuilder {
private BMWModel bmwModel = new BMWModel();
/**
* 设置顺序
*
* @param sequence
*/
@Override
public void setSequence(List<String> sequence) {
this.bmwModel.setSequence(sequence);
}
/**
* 得到模型
*
* @return
*/
@Override
public CarModel getCarModel() {
return this.bmwModel;
}
}
导演类
负责按照指定顺序生产模型
public class Director {
private List<String> sequence = new ArrayList<>();
private BenzBuilder benzBuilder = new BenzBuilder();
private BMWBuilder bmwBuilder = new BMWBuilder();
public BenzModel getABenzModel() {
this.sequence.clear();
this.sequence.add("start");
this.sequence.add("stop");
this.benzBuilder.setSequence(this.sequence);
return (BenzModel)this.benzBuilder.getCarModel();
}
public BMWModel getCBMWModel() {
this.sequence.clear();
this.sequence.add("alarm");
this.sequence.add("start");
this.sequence.add("stop");
this.bmwBuilder.setSequence(this.sequence);
return (BMWModel)this.bmwBuilder.getCarModel();
}
}
场景类
生产A 类型的奔驰车100万辆,C类型的宝马车200万辆
public class Client {
public static void main(String[] args) {
Director director = new Director();
for (int i = 0; i < 100; i++) {
director.getABenzModel().run();
}
for (int i = 0; i < 200; i++) {
director.getCBMWModel().run();
}
}
}
2、建造者模式定义
建造者模式(Builder Pattern)也叫做生成器模式。
Separate the construction of a complex object from its representation so that the same construction precess can create different representaions.(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
4个角色:
-
Product产品类
通常是实现了模板方法模式, 也就是有模板方法和基本方法。 -
Builder抽象创建者
规范产品的组建,一般是由子类实现。 -
ConcreteBuilder具体创建者
实现抽象类定义的所有方法, 并且返回一个组建好的对象。 例子中的BenzBuilder和BMWBuilder就属于具体建造者。 -
Director导演类
负责安排已有模块的顺序, 然后告诉Builder开始建造, 在上面的例子中就是我们的老大, ××公司找到老大, 说我要这个或那个类型的车辆模型, 然后老大就把命令传递给我, 我和我的团队就开始拼命地建造, 于是一个项目建设完毕了。
通用源代码
Product类
通常它是一个组合或继承(如模板方法模式) 产生的类
public class Product {
public void doSomething(){
//独立业务处理
}
}
抽象建造者
public abstract class Builder {
//设置产品的不同部分, 以获得不同的产品
public abstract void setPart();
//建造产品
public abstract Product buildProduct();
}
setPart方法是零件的配置, 什么是零件? 其他的对象, 获得一个不同零件, 或者不同的装配顺序就可能产生不同的产品。
具体建造者
public class ConcreteProduct extends Builder {
private Product product = new Product();
//设置产品零件
public void setPart(){
/*
* 产品类内的逻辑处理
*/
}
//组建一个产品
public Product buildProduct() {
return product;
}
}
注意:如果有多个产品类就有几个具体的建造者, 而且这多个产品类具有相同接口或抽象类。
导演类
public class Director {
private Builder builder = new ConcreteProduct();
//构建不同的产品
public Product getAProduct(){
builder.setPart();
/*
* 设置不同的零件, 产生不同的产品
*/
return builder.buildProduct();
}
}
3、建造者模式的应用
建造者模式的优点
封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节, 如例子中我们就不需要关心每一个具体的模型内部是如何实现的, 产生的对象类型就是CarModel。
建造者独立, 容易扩展
BenzBuilder和BMWBuilder是相互独立的, 对系统的扩展非常有利。
便于控制细节风险
由于具体的建造者是独立的, 因此可以对建造过程逐步细化, 而不对其他的模块产生任何影响。
建造者模式的使用场景
- 相同的方法, 不同的执行顺序, 产生不同的事件结果时, 可以采用建造者模式。
- 多个部件或零件,都可以装配到一个对象中, 但是产生的运行结果又不相同时, 则可以使用该模式。
- 产品类非常复杂, 或者产品类中的调用顺序不同产生了不同的效能, 这个时候使用建造者模式非常合适。
- 在对象创建过程中会使用到系统中的一些其他对象, 这些对象在产品对象的创建过程中不易得到时, 也可以采用建造者模式封装该对象的创建过程。 该种场景只能是一个补偿方法, 因为一个对象不容易获得, 而在设计阶段竟然没有发觉, 而要通过创建者模式柔化创建过程, 本身已经违反设计的最初目标。
建造者模式的注意事项
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方, 虽然同为创建类模式, 但是注重点不同。
建造者模式最主要的功能是基本方法的调用顺序安排, 也就是这些基本方法已经实现了, 通俗地说就是零件的装配, 顺序不同产生的对象也不同; 而工厂方法则重点是创建, 创建零件是它的主要职责, 组装顺序则不是它关心的。
建造者模式中还有一个角色没有说明, 就是零件, 建造者怎么去建造一个对象? 是零件的组装, 组装顺序不同对象效能也不同, 这才是建造者模式要表达的核心意义, 而怎么才能更好地达到这种效果呢? 引入模板方法模式是一个非常简单而有效的办法。
Builder模式
public class Person {
private String name;
private int age;
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Builder newBuilder() {
return new Builder(this);
}
public static class Builder {
private String name;
private int age;
public Builder() {
this.age = 0;
this.name = "";
}
Builder(Person person) {
this.name = person.name;
this.age = person.age;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Person create() {
return new Person(this);
}
}
}
将对象的创建与表示相分离,用户不用关心它的内在是什么样的。只需要知道传给他什么参数。在一些有很多参数的产品类中使用该模式,可以避免我们在构造函数中传入大量的默认参数来赋值的尴尬。
如果我们给Person类每一个参数都设置一个set方法,这样会增加Person类的功能和职责。违反了单一原则,不利于后期的维护。Builder模式更符合封装的原则,不对外公开属性的写操作!
以上是关于创建型模式之--创建者模式的主要内容,如果未能解决你的问题,请参考以下文章