裝飾者模式和建造者模式很相似,相似點都是內部把需求拼裝好之後才展示出來,那什麼情況下應該使用裝飾者模式,什麼情況下使用構建者模式呢?
我們先分別瞭解一下裝飾者和構建者,
裝飾者模式
What:
裝飾者模式又名包裝(Wrapper)模式。裝飾者模式動態地將責任附加到對象身上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案
Why:
優點:
1.裝飾者模式比繼承靈活性,在不改變原有對象的情況下給對象擴展功能,符合開閉原則
繼承關係是靜態的,在編譯的時候就已經決定了行爲,不便於控制增加行爲的方式和時機。
2.裝飾者模式可以動態使用不同的裝飾類排列組合,創造出多樣的行爲組合。
缺點:
1.裝飾模式會導致設計出大量的ConcreteDecorator類,增加系統的複雜性。
2.對於多次裝飾的對象,一旦出現錯誤,排錯繁瑣;
Where:
1.在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
2.需要動態地給一個對象增加功能,這些功能也可以動態地被撤銷。
3.當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴展和維護時。
How:
在學習使用裝飾者模式之前,先了解幾個重要角色。
Component(抽象構件):定義需要實現業務的抽象方法。
ConcreteComponent(具體構件):實現Component接口,用於定義具體的構建對象,可以給它增加額外的職責(方法)。
Decorator(抽象裝飾類):實現Component接口,並創建Component實例對象。用於給具體構件(ConcreteComponent)增加職責。
ConcreteDecorator(具體裝飾類):抽象裝飾類的子類,負責向構件添加新的職責。每一個具體裝飾類都定義了一些新的行爲,它可以調用在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充對象的行爲。
示例:以點餐爲例,我在麥*勞點餐可以根據我需求增加食物種類和數量
抽象構件角色:
public interface Food {
String getDescription();
}
具體構件角色:
public class BasicSet implements Food{
@Override
public String getDescription() {
return "漢堡 + 可樂";
}
}
抽象裝飾類角色:jkASDF
public abstract class Decorator implements Food {
private Food food;
public Decorator(Food food) {
this.food = food;
}
@Override
public String getDescription() {
return this.food.getDescription();
}
}
具體裝飾類角色
public class FrenchFries extends Decorator {
public FrenchFries(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 薯條";
}
}
public class FriedChicken extends Decorator {
public FriedChicken(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 炸雞";
}
}
public class IceCream extends Decorator {
public IceCream(Food food) {
super(food);
}
@Override
public String getDescription() {
return super.getDescription() + " + 冰淇淋";
}
}
測試類
1. public class Test {
2. public static void main(String[] args) {
3. Food food = new BasicSet();
4. Decorator setMealA = new FrenchFries(food);
5. setMealA = new FrenchFries(setMealA);
6. setMealA = new FriedChicken(setMealA);
7. setMealA = new IceCream(setMealA);
8. System.out.println("套餐A:" + setMealA.getDescription());
9. }
10. }
輸出結果:
套餐A:漢堡 + 可樂 + 薯條 + 薯條 + 炸雞 + 冰淇淋
建造者模式(Builder Pattern)
What:
建造者模式是將一個複雜的對象的構建與表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式隱藏了複雜對象的創建過程,它把複雜對象的創建過程加以抽象,通過子類繼承或者重載的方式,動態的創建具有複合屬性的對象。
Why:
優點:
1.遵循開閉原則。
2.對象的建造和表示分離,實現瞭解耦。
3.隱藏了對象的建造細節,用戶只需關心產品的表示,而不需要了解是如何創建產品的。
缺點:
1.如果構造者多,會有很多的建造類,難以維護。
2.產品的組成部分必須相同,這限制了其使用範圍。
Where:
1.隔離複雜對象的創建和使用,相同的方法,不同執行順序,產生不同事件結果
2.需要生成的產品對象的屬性相互依賴,需要指定其生成順序。
How:
在學習使用建造者模式之前,我們需要了解幾個概念。
Product:具體的產品。
Builder:抽象的建造方法。
ConcreteBuilder:具體的建造者。
Director(指揮官):調用具體構造者創建的產品對象,負責將客戶端傳來指令交給具體的建造者。
主要有以下兩種方式設計建造者模式:
一、通過Product,Builder,ConcreteBuilder,Director設計的建造者模式
computerElement類:具體的對象
/**
* 計算機元件
*/
public class ComputerElement {
private String CPU;
private String mainboard;
private String memory;
private String SSD;
private String power;
private String computerCase;
public ComputerElement() {
}
public ComputerElement(String CPU, String mainboard, String memory, String SSD, String power, String computerCase) {
this.CPU = CPU;
this.mainboard = mainboard;
this.memory = memory;
this.SSD = SSD;
this.power = power;
this.computerCase = computerCase;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("電腦組裝元件如下:\n");
sb.append("CPU:")
.append(CPU).append('\n');
sb.append("主板:")
.append(mainboard).append('\n');
sb.append("內存:")
.append(memory).append('\n');
sb.append("SSD:")
.append(SSD).append('\n');
sb.append("電源:")
.append(power).append('\n');
sb.append("機箱:")
.append(computerCase).append('\n');
sb.append("正在組裝中...").append('\n');
sb.append("組裝完成!").append('\n');
return sb.toString();
}
// 省略get、set方法
}
ComputerBuilder:抽象的建造方法
/**
* 組裝電腦抽象建造者
*/
public interface ComputerBuilder {
ComputerBuilder buildCPU(String CPU);
ComputerBuilder buildMainboard(String mainboard);
ComputerBuilder buildMemory(String memory);
ComputerBuilder buildSSD(String SSD);
ComputerBuilder buildPower(String power);
ComputerBuilder buildComputerCase(String computerCase);
ComputerElement build();
}
ComputerActualBuilder:具體的建造者
/**
* 組裝電腦具體建造者
*/
public class ComputerActualBuilder implements ComputerBuilder {
ComputerElement computerElement = new ComputerElement();
@Override
public ComputerBuilder buildCPU(String CPU) {
computerElement.setCPU(CPU);
return this;
}
@Override
public ComputerBuilder buildMainboard(String mainboard) {
computerElement.setMainboard(mainboard);
return this;
}
@Override
public ComputerBuilder buildMemory(String memory) {
computerElement.setMemory(memory);
return this;
}
@Override
public ComputerBuilder buildSSD(String SSD) {
computerElement.setSSD(SSD);
return this;
}
@Override
public ComputerBuilder buildPower(String power) {
computerElement.setPower(power);
return this;
}
@Override
public ComputerBuilder buildComputerCase(String computerCase) {
computerElement.setComputerCase(computerCase);
return this;
}
@Override
public ComputerElement build() {
return computerElement;
}
}
ComputerDirector:指揮官
/**
* 指揮官
*/
public class ComputerDirector {
private ComputerBuilder computerBuilder = new ComputerActualBuilder();
public ComputerElement build(String CPU, String mainboard, String memory, String SSD, String power, String computerCase) {
return computerBuilder.buildMainboard(mainboard)
.buildCPU(CPU)
.buildSSD(SSD)
.buildMemory(memory)
.buildPower(power)
.buildComputerCase(computerCase)
.build();
}
}
二、通過靜態內部類方式設計的建造者模式:
public class ComputerDIY {
private String CPU;
private String mainboard;
private String memory;
private String SSD;
private String power;
private String computerCase;
public ComputerDIY(ComputerBuilder computerBuilder) {
this.CPU = computerBuilder.CPU;
this.mainboard = computerBuilder.mainboard;
this.memory = computerBuilder.memory;
this.SSD = computerBuilder.SSD;
this.power = computerBuilder.power;
this.computerCase = computerBuilder.computerCase;
}
public String diy(){
final StringBuilder sb = new StringBuilder("電腦配置如下:\n");
sb.append(" CPU:")
.append(CPU).append('\n');
sb.append(" 主板:")
.append(mainboard).append('\n');
sb.append(" 內存:")
.append(memory).append('\n');
sb.append(" SSD:")
.append(SSD).append('\n');
sb.append(" 電源:")
.append(power).append('\n');
sb.append(" 機箱:")
.append(computerCase).append('\n');
sb.append("正在組裝中...").append('\n');
sb.append("組裝完成!").append('\n');
return sb.toString();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"CPU\":\"")
.append(CPU).append('\"');
sb.append(",\"mainboard\":\"")
.append(mainboard).append('\"');
sb.append(",\"memory\":\"")
.append(memory).append('\"');
sb.append(",\"SSD\":\"")
.append(SSD).append('\"');
sb.append(",\"power\":\"")
.append(power).append('\"');
sb.append('}');
return sb.toString();
}
public static class ComputerBuilder{
private String CPU;
private String mainboard;
private String memory;
private String SSD;
private String power;
private String computerCase;
public ComputerBuilder buildCPU(String CPU) {
this.CPU = CPU;
return this;
}
public ComputerBuilder buildMainboard(String mainboard) {
this.mainboard = mainboard;
return this;
}
public ComputerBuilder buildMemory(String memory) {
this.memory = memory;
return this;
}
public ComputerBuilder buildSSD(String SSD) {
this.SSD = SSD;
return this;
}
public ComputerBuilder buildPower(String power) {
this.power = power;
return this;
}
public ComputerBuilder buildComputerCase(String computerCase) {
this.computerCase = computerCase;
return this;
}
public ComputerDIY build() {
return new ComputerDIY(this);
}
}
}
public class Test {
public static void main(String[] args) {
ComputerDIY computerDIY = new ComputerDIY.ComputerBuilder()
.buildCPU("Intel酷睿六核處理器i5-8400")
.buildMainboard("Intel B360")
.buildMemory("16G")
.buildSSD("16G")
.buildPower("美商海盜船")
.buildComputerCase("普通機箱")
.build();
System.out.println(computerDIY.diy());
}
}
總結
建造者模式適合於創建的對象較複雜,由多個部件構成,各部件面臨着複雜的變化,但構件間的建造順序是穩定的;創建複雜對象的算法獨立於該對象的組成部分以及它們的裝配方式,即產品的構建過程和最終的表示是獨立的。
我們學完兩者 看一下兩者有什麼相同點和不同點吧
相同點:
1:都是不改變原有對象的基礎上對對象進行二次封裝
不同點:
1:建造者模式屬於創建型模式 :創建型模式(創建型設計模式就是把對象的創建和對象的使用分離開。)
裝飾者屬於結構性模式 :結構性模式( 是描述如何將類對象結合在一起,形成一個更大的結構,結構模式描述兩種不同的東 西:類與類的實例。故可以分爲類結構模式和對象結構模式。)
2:建造者模式是對複雜對象整體功能的一個組裝,裝飾者模式是表面外部的裝扮,基礎功能還是屬於對象本身。