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

建造者模式

定义

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

结构

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

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

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

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

类图

使用场景

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)

由上图我们可以看出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 <tt>char</tt> sequences and values can be appended.  The
 * <tt>Appendable</tt> interface must be implemented by any class whose
 * instances are intended to receive formatted output from a {@link
 * java.util.Formatter}.
 *
 * <p> The characters to be appended should be valid Unicode characters as
 * described in <a href="Character.html#unicode">Unicode Character
 * Representation</a>.  Note that supplementary characters may be composed of
 * multiple 16-bit <tt>char</tt> values.
 *
 * <p> Appendables are not necessarily safe for multithreaded access.  Thread
 * safety is the responsibility of classes that extend and implement this
 * interface.
 *
 * <p> 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 <tt>Appendable</tt>.
     *
     * <p> Depending on which class implements the character sequence
     * <tt>csq</tt>, the entire sequence may not be appended.  For
     * instance, if <tt>csq</tt> 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 <tt>csq</tt> is
     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
     *         appended to this Appendable.
     *
     * @return  A reference to this <tt>Appendable</tt>
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    Appendable append(CharSequence csq) throws IOException;

    /**
     * Appends a subsequence of the specified character sequence to this
     * <tt>Appendable</tt>.
     *
     * <p> An invocation of this method of the form <tt>out.append(csq, start,
     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
     * exactly the same way as the invocation
     *
     * <pre>
     *     out.append(csq.subSequence(start, end)) </pre>
     *
     * @param  csq
     *         The character sequence from which a subsequence will be
     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
     *         will be appended as if <tt>csq</tt> contained the four
     *         characters <tt>"null"</tt>.
     *
     * @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 <tt>Appendable</tt>
     *
     * @throws  IndexOutOfBoundsException
     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
     *          <tt>csq.length()</tt>
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    Appendable append(CharSequence csq, int start, int end) throws IOException;

    /**
     * Appends the specified character to this <tt>Appendable</tt>.
     *
     * @param  c
     *         The character to append
     *
     * @return  A reference to this <tt>Appendable</tt>
     *
     * @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;
    }

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值