1. 程式人生 > >Java常用設計模式————建造者模式

Java常用設計模式————建造者模式

引言

建造者模式(Builder Pattern)使用多個簡單物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建造型模式,它提供了一種建立物件的最佳方式。

一個Builder會一步步構建最終的物件。該Builder類是獨立於其他物件的。

實現概要

建造者模式的實現並沒有一個特別經典的套路,原因是在多數情況下複雜物件的構建往往千奇百怪。但為了更好的理解建造者模式使用的場景,我們假設如下的功能需要:

因為建造者模式就是為了構建複雜物件,為了更加貼近這一點,以午餐(Meal)作為最終要被構建的物件,我們假設:午餐中分為食物(Item)包裝(Packing)—>食物包含漢堡(Burger)

冷飲(ColdDrink)兩種;漢堡雞肉漢堡(ChickenBurger)蔬菜漢堡(VegBurger)之分;冷飲可口可樂(Coke)百事可樂(Pepsi)之分;包裝又分為瓶裝(Bottle)袋裝(Wrapper)兩種。

如果你看不懂上面的描述,或者已經準備關閉瀏覽器去做眼睛保健操,那麼下面的結構圖可能對你有所幫助:

實現過程

一、建立基礎介面

建立食物介面及具體實現類,建立包裝介面及具體包裝類:

public interface Item {
    /** 食物名稱*/
    String name();
    /** 包裝*/
    Packing packing();
    /** 總價*/
    float price();
}
public abstract class Burger implements Item {

    @Override
    public Packing packing() {
        return new Wrapper();
    }
}
public class ChickenBurger extends Burger {

    @Override
    public String name() {
        return "Chicken Burger";
    }

    @Override
    public float price() {
        return 50.5f;
    }
}
public class VegBurger extends Burger {

    @Override
    public String name() {
        return "Veg Burger";
    }

    @Override
    public float price() {
        return 25.0f;
    }
}
public abstract class ColdDrink implements Item {

    @Override
    public Packing packing() {
        return new Bottle();
    }
}
public class Coke extends ColdDrink {

    @Override
    public String name() {
        return "Coke";
    }
    
    @Override
    public float price() {
        return 30.0f;
    }
}
public class Pepsi extends ColdDrink {

    @Override
    public String name() {
        return "Pepsi";
    }
    
    @Override
    public float price() {
        return 35.0f;
    }
}
public interface Packing {
    String pack();
}
public class Bottle implements Packing {

    @Override
    public String pack() {
        return "Bottle";
    }
}
public class Wrapper implements Packing {

    @Override
    public String pack() {
        return "Wrapper";
    }
}

二、建立目標型別

此例中,目標型別即午餐類(Meal)

public class Meal {
    private List<Item> items = new ArrayList<Item>();

    public Meal addAll(List<? extends Item> items) {
        this.items.addAll(items);
        return this;
    }

    public Double getSum() {
        return this.items.stream()
                         .collect(Collectors.summarizingDouble(Item::price))
                         .getSum();
    }
    
    public Double getAverage() {
        return this.items.stream()
                         .collect(Collectors.summarizingDouble(Item::price))
                         .getAverage();
    }

    public void showItems() {
        this.items.forEach(item -> {
            System.out.print("Item : " + item.name());
            System.out.print(", Packing : " + item.packing()
                                                  .pack());
            System.out.println(", Price : " + item.price());
        });
    }
}

三、建立建造者類

public class MealBuilder {

    public Meal prepareMeal(Item... items) {
        return new Meal().addAll(Arrays.asList(items));
    }
}

四、測試

public class BuilderPatternDemo {

    public static void main(String[] args) {
        MealBuilder mealBuilder = new MealBuilder();
        
        Meal vegMeal = mealBuilder.prepareMeal(new VegBurger(), new Coke());
        System.out.println("Veg Meal");
        vegMeal.showItems();
        System.out.println("Total Cost: " + vegMeal.getSum());

        Meal nonVegMeal = mealBuilder.prepareMeal(new ChickenBurger(), new Pepsi());
        System.out.println("\n\nNon-Veg Meal");
        nonVegMeal.showItems();
        System.out.println("Total Cost: " + nonVegMeal.getSum());
    }
}

執行結果:

總結

意圖:建造者模式的用意就是將一個複雜的構建與其表示相分離,使得同樣的構建過程可以建立不同的表示,例如本例中相同的建立午餐的方式,但使用不同的基礎物件,最終得出不一樣的套餐。

使用場景:一些基礎部件不會變,而其組合經常變化的時候。主要解決軟體系統中,有時候會面臨“一個複雜物件”的建立工作,其通常由多個子物件用一定的演算法構成。由於需求的變化,這個複雜物件的各個部件經常面臨著劇烈的變化,但將它們組合在一起的演算法相對穩定。

優點:建造者獨立,易擴充套件;便於控制細節風險。

缺點:產品必須有共同點,範圍有限制;內部變化複雜,會有很多建造類。

鳴謝

建造者模式