Java設計模式之創建型模式:建造者(生成器)模式

一、基本介紹

建造者模式(Build Pattern)又稱生成器模式,該模式封裝一個產品的構造過程,一步一步地創建出一個複雜的對象,它允許用戶通過指定複雜對象的類型和具體內容來構建對象,不需要知道內部的構建細節。

下面是建造者的原理UML類圖:在這裏插入圖片描述
建造者模式的四個角色說明:

  1. Product(產品對象):一個具體的產品對象
  2. Builder(抽象建造者):用於創建一個產品對象的各個部件指定的接口/抽象類
  3. ConcreteBuilder(具體建造者):實現接口,構建和裝配產品的各個部件。
  4. Director(指揮者):用於創建一個複雜的對象,它主要有兩個作用:隔離客戶與對象的生產過程和負責控制產品對象的生產過程。指揮者針對抽象建造者編程,客戶端只需要知道具體建造者的類型,即可通過指揮者類調用建造者的相關方法,返回一個完整的產品對象。

二、使用

下面應用建造者模式來解決一個實際案例

1.場景

假設你在廣州做一個導遊,現在你需要爲遊客制定多個“羊城一日遊”的行程安排的計劃,其中每個計劃去的景點可能不太一樣,另外如果是外地的遊客則需要提供旅館住宿。
所以需要一個彈性的數據結構,代表客人的規劃以及所有的變化。要創建這樣的計劃,就需要使用建造者模式來實現創建複雜的結構的同時,又不會和創建它的步驟混在一起。

2.UML類圖設計

在這裏插入圖片描述
其中PlanA不包含住宿,PlanB包含住宿

3.代碼實現

Plan類,擔當產品對象的角色

public class Plan {
	public String morningPlan;
	public String afternoonPlan;
	public String nightPlan;
	public String sleepPlan;
//省略getter和setter方法
//省略toString方法

Director類,擔當指揮者的角色

public class Director {
	AbstractBuilder planBuilder;

	public Director(AbstractBuilder planBuilder) {
		// TODO Auto-generated constructor stub
		this.planBuilder = planBuilder;
	}

	public void setPlanBuilder(AbstractBuilder planBuilder) {
		this.planBuilder = planBuilder;
	}

	public Plan constructPlan() {
		System.out.println("計劃制定:");
		planBuilder.arrangeMorning();
		planBuilder.arrangeAfternoon();
		planBuilder.arrangeNight();
		planBuilder.arrangeSleep();
		return planBuilder.getPlan();
	}
}

AbstractPlanBuilder類,擔當抽象建造者的角色

public abstract class AbstractBuilder {
	Plan plan = new Plan();

	public abstract void arrangeMorning();

	public abstract void arrangeAfternoon();

	public abstract void arrangeNight();

	public abstract void arrangeSleep();

	public Plan getPlan() {
		return plan;
	}
}

PlanABuilder,PlanBBuilder都擔當具體建造者的角色

public class PlanABuilder extends AbstractBuilder {

	@Override
	public void arrangeMorning() {
		// TODO Auto-generated method stub
		plan.setMorningPlan("出發時間:8:00,目的地:白雲山");
		System.out.println("已制定好早上的計劃");
	}

	@Override
	public void arrangeAfternoon() {
		// TODO Auto-generated method stub
		plan.setAfternoonPlan("出發時間:12:00,目的地:長隆歡樂世界");
		System.out.println("已制定好下午的計劃");
	}

	@Override
	public void arrangeNight() {
		// TODO Auto-generated method stub
		plan.setNightPlan("出發時間: 20:00 ,目的地:廣州塔");
		System.out.println("已制定好晚上的計劃");
	}
	@Override
	public void arrangeSleep() {
		System.out.println("該計劃不安排住宿");
	}
}

public class PlanBBuilder extends AbstractBuilder {

	@Override
	public void arrangeMorning() {
		// TODO Auto-generated method stub
		plan.setMorningPlan("出發時間:8:15,目的地:大夫山");
		System.out.println("已制定好早上的計劃");
	}

	@Override
	public void arrangeAfternoon() {
		// TODO Auto-generated method stub
		plan.setAfternoonPlan("出發時間:11:30,目的地:長隆歡樂世界");
		System.out.println("已制定好下午的計劃");
	}

	@Override
	public void arrangeNight() {
		// TODO Auto-generated method stub
		plan.setNightPlan("出發時間: 20:00 ,目的地:廣州塔");
		System.out.println("已制定好晚上的計劃");
	}

	@Override
	public void arrangeSleep() {
		System.out.println("晚上住宿在白天鵝賓館");
	}

}

Client類作爲客戶類,只需調用Director的consructPlan即可完成計劃對象的創建

public class Client {
	public static void main(String[] args) {
		Director director = new Director(new PlanABuilder());
		Plan p1 = director.constructPlan();
		System.out.println("計劃詳情:" + p1);
		director.setPlanBuilder(new PlanBBuilder());
		Plan p2 = director.constructPlan();
		System.out.println("計劃詳情:" + p2);
	}
}

程序運行結果:
在這裏插入圖片描述

三、典型應用

java.lang.StringBuilder中的建造者模式
StringBuilder類的繼承和實現關係,如圖:
在這裏插入圖片描述
Appendable接口定義了三個append方法,其擔當抽象建造者的角色,定義了抽象方法。

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

AbstractStringBuilder實現了Appendable接口的三個方法,AbstractStringBuilder類擔當了具體建造者的角色,當由於其是抽象類,所以不能實例化。

abstract class AbstractStringBuilder implements Appendable, CharSequence {
//省略
    @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());
    }
      @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;
    }

    @Override
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
    //省略
  } 

StringBuilder即擔當了指揮者角色,同時擔當了具體的建造者的角色,還是產品對象。其建造方法是由其父類AbstractStringBuilder來實現,下面三個重載的append方法都是建造方法,只不過比較簡單,只有一個方法調用。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
//省略
  @Override
    public StringBuilder append(CharSequence s) {
        super.append(s);
        return this;
    }
    @Override
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
    
    @Override
    public StringBuilder append(char c) {
        super.append(c);
        return this;
    }
   }
   //省略

四、總結

  • 建造者模式的優點:
  1. 在建造者模式中,向客戶端隱藏產品內部的表現,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象
  2. 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者, 用戶使用不同的具體建造者即可得到不同的產品對象 。
  3. 可以更加精細地控制產品的創建過程 。將複雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
  4. 增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合“開閉原則”。
  • 建造者模式的缺點:
  1. 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
  2. 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
  • 建造者模式與抽象工廠模式的比較:

與抽象工廠模式相比, 建造者模式返回一個組裝好的完整產品 ,而抽象工廠模式返回一系列相關的產品,這些產品位於不同的產品等級結構,構成了一個產品族。
在抽象工廠模式中,客戶端實例化工廠類,然後調用工廠方法獲取所需產品對象,而在建造者模式中,客戶端可以不直接調用建造者的相關方法,而是通過指揮者類來指導如何生成對象,包括對象的組裝過程和建造步驟,它側重於一步步構造一個複雜對象,返回一個完整的對象

如果將抽象工廠模式看成 汽車配件生產工廠 ,生產一個產品族的產品,那麼建造者模式就是一個 汽車組裝工廠 ,通過對部件的組裝可以返回一輛完整的汽車。

參考:
1.4.建造者模式
2.設計模式 | 建造者模式及典型應用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章