设计模式-建造者模式(java代码案例)以及JDK类库中的建造者模式

建造者模式

定义

将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

结构

抽象建造者类(builder):为创建product对象而指定各个组件的抽象接口

具体建造类(concreteBuilder):实现builder接口,重写方法构建不同的表示

产品类(product):具体的产品

指挥者类(director):构建一个使用builder接口的对象

类图

设计模式-建造者模式(java代码案例)以及JDK类库中的建造者模式_第1张图片

使用场景

1.创建的对象比较复杂 2.需要生成的对象内部属性本身相互依赖

案例

以建造人为例,分为建造瘦子和胖子,它们的步骤都是先造头,再造身体,其次胳膊,最后腿,然而他俩的区别是具体建造类的实现不同

Person类

package com.headfirst.buildermode.dao;

public class Person {

	public String head;
	public String body;
	public String arms;
	public String legs;
	public String getHead() {
		return head;
	}
	public void setHead(String head) {
		this.head = head;
	}
	public String getBody() {
		return body;
	}
	public void setBody(String body) {
		this.body = body;
	}
	public String getArms() {
		return arms;
	}
	public void setArms(String arms) {
		this.arms = arms;
	}
	public String getLegs() {
		return legs;
	}
	public void setLegs(String legs) {
		this.legs = legs;
	}
	
	@Override
	public String toString() {
		return this.getHead()+this.getBody()+this.getArms()+this.getLegs();
	}
	
}

建造者抽象类

package com.headfirst.buildermode.interfaces;

import com.headfirst.buildermode.dao.Person;

/**
 *	定义了具体实现类的抽象接口
 *	1.建造不同的人(胖子和瘦子)
 *	2.建造者模式是类创建型的模式
 */
public interface IBuilder {
	
	public abstract void createHead();
	public abstract void createBody();
	public abstract void createArms();
	public abstract void createLegs();
	public abstract Person buildPerson();
}

(瘦子)具体建造者类

package com.headfirst.buildermode.dao;

import com.headfirst.buildermode.interfaces.IBuilder;

public class ThinPersonBuilder implements IBuilder {

	private Person person = null;
	
	public ThinPersonBuilder() {
		if(person == null){
			person = new Person();
		}
	}
	
	@Override
	public void createHead() {
		person.setHead("我");
	}

	@Override
	public void createBody() {
		person.setBody("是");
	}

	@Override
	public void createArms() {
		person.setArms("瘦");
	}

	@Override
	public void createLegs() {
		person.setLegs("子");
	}

	@Override
	public Person buildPerson() {
		return person;
	}

}

(胖子)具体建造类

package com.headfirst.buildermode.dao;

import com.headfirst.buildermode.interfaces.IBuilder;

public class FatPersonBuilder implements IBuilder {

private Person person = null;
	
	public FatPersonBuilder() {
		if(person == null){
			person = new Person();
		}
	}
	
	@Override
	public void createHead() {
		person.setHead("我");
	}

	@Override
	public void createBody() {
		person.setBody("是");
	}

	@Override
	public void createArms() {
		person.setArms("胖");
	}

	@Override
	public void createLegs() {
		person.setLegs("子");
	}

	@Override
	public Person buildPerson() {
		return person;
	}

}

指挥者类

package com.headfirst.buildermode.dao;

import com.headfirst.buildermode.interfaces.IBuilder;

public class BuilderDirector {

	private IBuilder ibuilder = null;
	
	public BuilderDirector(IBuilder ib){
		if(ibuilder == null){
			ibuilder = ib;
		}
	}
	
	public Person buildPerson(){
		ibuilder.createHead();
		ibuilder.createBody();
		ibuilder.createArms();
		ibuilder.createLegs();
		return ibuilder.buildPerson();
	}
	
}

测试类

	public static void main(String[] args) {
		ThinPersonBuilder thinPersonBuilder = new ThinPersonBuilder();
		BuilderDirector director = new BuilderDirector(thinPersonBuilder);
		Person thinPerson = director.buildPerson();
		System.out.println(thinPerson.toString());
		
		FatPersonBuilder fatPersonBuilder = new FatPersonBuilder();
		BuilderDirector director2 = new BuilderDirector(fatPersonBuilder);
		Person fatPerson = director2.buildPerson();
		System.out.println(fatPerson.toString());
	}

测试结果

优点

1.将创建代码和表示代码分离,有利于解耦合

2.当需要增加新的功能时,只需要增加一个新的类,符合开闭原则

缺点

受限于产品必须有共同点,否则不适用建造者模式

JDK类库中的建造者模式

java.lang.StringBuilder#append(Character c)

设计模式-建造者模式(java代码案例)以及JDK类库中的建造者模式_第2张图片

由上图我们可以看出StringBuilder继承了AbstractStringBuilder,而AbstractStringBuilder实现了appendable。

StringBuilder:指挥者类,持有具体建造者的引用,由于StringBuilder继承了AbstractStringBuilder,这里StringBuilder通过super来作为具体建造者的引用。

AbstractStringBuilder:具体建造者,它实现了appendable接口的append(Character c)方法。

appendable:抽象建造者,定义了创建对象的接口。

StringBuilder的append(Character c)方法:

    /**
     */
    public StringBuilder append(CharSequence s) {
        if (s == null)
            s = "null";
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof StringBuffer)
            return this.append((StringBuffer)s);
        if (s instanceof StringBuilder)
            return this.append((StringBuilder)s);
        return this.append(s, 0, s.length());
    }

    /**
     * @throws     IndexOutOfBoundsException {@inheritDoc}
     */
    public StringBuilder append(CharSequence s, int start, int end) {
        //调用具体建造者的append方法
        super.append(s, start, end);
        return this;
    }

AbstractStringBuilder的append(CharSequence s, int start, int end) 方法:

    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;
    }

appendable抽象建造者:

/**
 * An object to which char sequences and values can be appended.  The
 * Appendable interface must be implemented by any class whose
 * instances are intended to receive formatted output from a {@link
 * java.util.Formatter}.
 *
 * 

The characters to be appended should be valid Unicode characters as * described in Unicode Character * Representation. Note that supplementary characters may be composed of * multiple 16-bit char values. * *

Appendables are not necessarily safe for multithreaded access. Thread * safety is the responsibility of classes that extend and implement this * interface. * *

Since this interface may be implemented by existing classes * with different styles of error handling there is no guarantee that * errors will be propagated to the invoker. * * @since 1.5 */ public interface Appendable { /** * Appends the specified character sequence to this Appendable. * *

Depending on which class implements the character sequence * csq, the entire sequence may not be appended. For * instance, if csq is a {@link java.nio.CharBuffer} then * the subsequence to append is defined by the buffer's position and limit. * * @param csq * The character sequence to append. If csq is * null, then the four characters "null" are * appended to this Appendable. * * @return A reference to this Appendable * * @throws IOException * If an I/O error occurs */ Appendable append(CharSequence csq) throws IOException; /** * Appends a subsequence of the specified character sequence to this * Appendable. * *

An invocation of this method of the form out.append(csq, start, * end) when csq is not null, behaves in * exactly the same way as the invocation * *

     *     out.append(csq.subSequence(start, end)) 
* * @param csq * The character sequence from which a subsequence will be * appended. If csq is null, then characters * will be appended as if csq contained the four * characters "null". * * @param start * The index of the first character in the subsequence * * @param end * The index of the character following the last character in the * subsequence * * @return A reference to this Appendable * * @throws IndexOutOfBoundsException * If start or end are negative, start * is greater than end, or end is greater than * csq.length() * * @throws IOException * If an I/O error occurs */ Appendable append(CharSequence csq, int start, int end) throws IOException; /** * Appends the specified character to this Appendable. * * @param c * The character to append * * @return A reference to this Appendable * * @throws IOException * If an I/O error occurs */ Appendable append(char c) throws IOException; }

java.lang.StringBuffer#append(Character c)

StringBuffer本质上和StringBuilder是一样的,唯一的区别就是StringBuffer的append方法上加了synchronized,所以StringBuffer是线程安全的,而StringBuilder不是线程安全的。

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @since      1.5
     */
    public synchronized StringBuffer append(CharSequence s, int start, int end)
    {
        super.append(s, start, end);
        return this;
    }

    public synchronized StringBuffer append(char[] str) {
        super.append(str);
        return this;
    }

 

你可能感兴趣的:(设计模式,设计模式轻松学)