1. 建造者模式
1.1 定义
建造者模式(Builder Pattern)使用
多个简单的对象一步一步构建成一个复杂的对象
。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
它与工厂模式一样,也是一种创建型设计模式。不同点在于:它创建的是一种产品,一个复杂的对象。而工厂模式它创建的是一系列产品。它将一个对象的构建与表示分离。建造者模式更加关注与零件装配的顺序。
1.2 介绍
建造者模式是将一个复杂的构建与其表示分离,使得同样的构建过程可以创建不同的表示。也就是实现局部与整体的解耦。主要解决在面临“一个复杂对象”的创建的工作的时候,通常由各个部分的子对象用一定的算法构成
。由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
一般建造者都有以下几种角色:
- 产品(Product)角色:具体的产品对象。
- 抽象建造者(Builder)角色:定义一个抽象/接口类,用来规范产品对象的各个组成成分的建造。
- 具体建造者(ConcreteBuilder)角色:用来直接创建产品的实例,即实现抽象接口类。实现接口所要求的两种方法:1.建造方法。2.返还结构方法。一般有多少实例就有多少相应的建造方法。
- 导演者(Director)角色:用来调用这个角色的类的具体建造者角色已创建产品对象。其没有产品类的具体知识。
建造者模式主要用于一些基本组件不变,而其组合经常变化的时候。
2. 代码实现
2.1. 普通实例
小例子:去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
1.产品类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SetFoods {
private String hamburg;
private String drink;
private String friedFood;
}
2.抽象建造者,即定义事物的接口或者抽象类
public interface AbstractFabricationFoods {
void fabricationHamburg();
void fabricationDrink();
void fabricationFriedFoods();
SetFoods fabricationPackage();
}
3.具体建造者,即具体的实现类
//套餐一
public class FabricationPackage1 implements AbstractFabricationFoods {
@Override
public void fabricationHamburg() {
System.out.println("制作爆浆芝士汉堡");
}
@Override
public void fabricationDrink() {
System.out.println("制作可乐");
}
@Override
public void fabricationFriedFoods() {
System.out.println("制作炸鸡");
}
@Override
public SetFoods fabricationPackage() {
return new SetFoods();
}
}
//套餐二
public class FabricationPackage2 implements AbstractFabricationFoods {
@Override
public void fabricationHamburg() {
System.out.println("制作芝士汉堡");
}
@Override
public void fabricationDrink() {
System.out.println("制作雪碧");
}
@Override
public void fabricationFriedFoods() {
System.out.println("制作炸鸡翅");
}
@Override
public SetFoods fabricationPackage() {
return new SetFoods();
}
}
4.导演,即制作事物的决定者
public class FoodsDirector {
public SetFoods fabricationFoods(AbstractFabricationFoods aff) {
aff.fabricationHamburg();
aff.fabricationDrink();
aff.fabricationFriedFoods();
return aff.fabricationPackage();
}
}
5.测试类
public class Test {
public static void main(String[] args) {
FoodsDirector fd=new FoodsDirector();
fd.fabricationFoods(new FabricationPackage1());
fd.fabricationFoods(new FabricationPackage2());
}
}
/**
*制作爆浆芝士汉堡
* 制作可乐
* 制作炸鸡
* 制作芝士汉堡
* 制作雪碧
* 制作炸鸡翅
*/
2.2 StringBuilder的源码分析
具体来说,StirngBuilder就是一个典型的建造者模式的实现,JDK中的StirngBuilder提供了append()追加方法,这是一种链式调用,最后通过toString()返回该对象的字符串类型。
1.抽象类
public abstract class MyAbstractStringBuilder {
char[] value;
int count;
//创造一个大小为capacity的空间
public MyAbstractStringBuilder(int capacity) {
count = 0;
value = new char[capacity];
}
//添加字符串
public MyAbstractStringBuilder append(String str) {
if (str == null)
return null;
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//确保内部容量足够
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
//扩展容量 minimumCapacity代表最小容量
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length << 1) + 2; //相当于value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError(); //内存不足错误
//Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
//Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
}
2.实现类
public class MyStringBuilder extends MyAbstractStringBuilder {
public MyStringBuilder() {
super(16);
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
@Override
public MyStringBuilder append(String str) {
super.append(str);
return this;
}
}
3.测试类
public class Test2 {
public static void main(String[]args){
MyStringBuilder sb = new MyStringBuilder();
sb.append("(").append("hello").append(",").append("world").append(")").toString();
System.out.println(sb);
}
}
/**
* (hello,world)
*/
此处只实现了具体的添加字符串的方法,我们能看到可以通过append()来添加,进而获得自己想得到的字符串。
3. 优/缺点
建造者模式对产品的创建和产品的实现进行了解耦,使得可以通过相同的方法创建出不同的对象,用户只需要指定对象的类型和内容就可以得到想要的结果。主要在需要生成的对象具有复杂的内部结构
或者需要生成的对象内部属性本身相互依赖
时使用。
优点:
- 建造者独立,易扩展。
- 便于控制细节风险。
缺点:
- 产品必须有共同点,范围有限制。
- 如内部变化复杂,会有很多的建造类。