这是我参与更文挑战的第22天,活动详情查看: 更文挑战
设计模式
建造者模式
比如我们建造房子,建房子的过程有打桩、砌墙、封顶,房子的类型有平房、楼房、别墅
我们的代码这样写的
AbsHouse
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public abstract class AbsHouse {
public abstract void layingFoundation();
public abstract void buildWall();
public abstract void sealRoof();
public void build() {
layingFoundation();
buildWall();
sealRoof();
}
}
Bungalow
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public class Bungalow extends AbsHouse {
@Override
public void layingFoundation() {
System.out.println("平房筑基");
}
@Override
public void buildWall() {
System.out.println("平房筑墙");
}
@Override
public void sealRoof() {
System.out.println("平房封顶");
}
}
main
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public class Builder {
public static void main(String[] args) {
Bungalow bungalow = new Bungalow();
bungalow.build();
}
}
这种方式 ,耦合性较强,将房子的建造过程全部封装在一起,所以需要将房子和房子建造过程进行解耦
产品角色House
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.23 14:46
*/
public class House {
private String foundation;
private String wall;
private String roof;
public String getFoundation() {
return foundation;
}
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
}
抽象的建造者HouseBuilder
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.23 14:46
*/
public abstract class HouseBuilder {
protected House house = new House();
public abstract void layingFoundation();
public abstract void buildWall();
public abstract void sealRoof();
public House buildHouse() {
return house;
}
}
具体建造者Bungalow
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public class Bungalow extends HouseBuilder {
@Override
public void layingFoundation() {
System.out.println("平房筑基");
}
@Override
public void buildWall() {
System.out.println("平房筑墙");
}
@Override
public void sealRoof() {
System.out.println("平房封顶");
}
}
以及另一个具体的建造者Villa
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 14:49
*/
public class Villa extends HouseBuilder {
@Override
public void layingFoundation() {
System.out.println("别墅筑基");
}
@Override
public void buildWall() {
System.out.println("别墅筑墙");
}
@Override
public void sealRoof() {
System.out.println("别墅封顶");
}
}
指挥者
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.23 14:46
*/
public class HouseDirector {
HouseBuilder houseBuilder = null;
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public House constructHouse() {
houseBuilder.layingFoundation();
houseBuilder.buildWall();
houseBuilder.sealRoof();
return houseBuilder.buildHouse();
}
}
main
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public class Builder {
public static void main(String[] args) {
Villa villa = new Villa();
HouseDirector houseDirector = new HouseDirector(villa);
House house = houseDirector.constructHouse();
Bungalow bungalow =new Bungalow();
houseDirector.setHouseBuilder(bungalow);
House house1 =houseDirector.constructHouse();
}
}
当我们增加楼房时,只需要增加TallBuilding即可
package com.wangscaler.builder;
/**
* @author wangscaler
* @date 2021.06.24 13:56
*/
public class TallBuilding extends HouseBuilder {
@Override
public void layingFoundation() {
System.out.println("楼房筑基");
}
@Override
public void buildWall() {
System.out.println("楼房筑墙");
}
@Override
public void sealRoof() {
System.out.println("楼房封顶");
}
}
源码中的建造者模式
JDK中的StringBuilder
我们打开源码
package java.lang;
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string builder is {@code 16} plus the length of the
* {@code CharSequence} argument.
*
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
@Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
@Override
public StringBuilder append(char[] str) {
super.append(str);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
@Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
@Override
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
@Override
public StringBuilder append(float f) {
super.append(f);
return this;
}
@Override
public StringBuilder append(double d) {
super.append(d);
return this;
}
/**
* @since 1.5
*/
@Override
public StringBuilder appendCodePoint(int codePoint) {
super.appendCodePoint(codePoint);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, Object obj) {
super.insert(offset, obj);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int dstOffset, CharSequence s) {
super.insert(dstOffset, s);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int dstOffset, CharSequence s,
int start, int end)
{
super.insert(dstOffset, s, start, end);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, char c) {
super.insert(offset, c);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, int i) {
super.insert(offset, i);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, long l) {
super.insert(offset, l);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, float f) {
super.insert(offset, f);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int offset, double d) {
super.insert(offset, d);
return this;
}
@Override
public int indexOf(String str) {
return super.indexOf(str);
}
@Override
public int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);
}
@Override
public int lastIndexOf(String str) {
return super.lastIndexOf(str);
}
@Override
public int lastIndexOf(String str, int fromIndex) {
return super.lastIndexOf(str, fromIndex);
}
@Override
public StringBuilder reverse() {
super.reverse();
return this;
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
}
/**
* readObject is called to restore the state of the StringBuffer from
* a stream.
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject();
}
}
发现他继承了AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/**
* @since 1.8
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
}
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
}
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(long l) {
if (l == Long.MIN_VALUE) {
append("-9223372036854775808");
return this;
}
int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(float f) {
FloatingDecimal.appendTo(f,this);
return this;
}
public AbstractStringBuilder append(double d) {
FloatingDecimal.appendTo(d,this);
return this;
}
}
以append方法为例,我们发现他是实现的Appendable这个抽象类
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*/
package java.lang;
import java.io.IOException;
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
这个Appendable就可以说是我们建造者模式的抽象建造者,在这里创建了抽象方法,那么我们的AbstractStringBuilder就是具体建造者实现了这些抽象方法,StringBuilder既充当了指挥者角色
Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
又充当了具体的建造者
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
总结
建造者四种角色
- 产品角色:包含多个组成部件(筑基、筑墙、封顶)的一个具体的对象(房子)
- 抽象建造者:包含创建产品各个部件(筑基、筑墙、封顶)的抽象方法的接口,一般还包含返回最终产品的方法(buildHouse)。
- 具体建造者:实现接口,实现构建装配各个部件的方法(筑基、筑墙、封顶)
- 指挥者:调用构建部件的方法完成对象的创建(组装房子)。
使用场景:
1、建造者创建的产品一般具有较多的共同点(盖楼都是筑基、筑墙、封顶),如果差异比较大,则不适合使用。
2、创建简单的对象一般使用工厂模式,创建复杂对象(多于5个组件)一般使用建造者模式
3、相同的方法,不同的执行顺序,产生不同的结果。
4、 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
5、产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
6、初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。