---
# System prepended metadata

title: Design Pattern

---

# Design Pattern



## 什麼是Design Pattern?

@StanShih 

在程式設計中，經常遇到相同的設計問題，許多設計可以解決這些重複出現的問題，但隨著時間推進，某些設計因為更加的靈活，而優於了其他的設計。而這些設計被整理歸類，進而發展出了Design Pattern。Design Pattern即是針對這些反覆出現的問題而提出的解決方案。

Design Pattern一書中介紹了 23 種模式，依照不同的狀況，使用不同的模式，解決不同的問題。而所謂的Design Pattern並非一組source code，他為一個概念。

```markmap
# Design Pattern
## 創建型模式 --對象創建和使用分離
### 單例模式 Singleton
### 工廠模式 Factory
### 抽象工廠模式 Abstract Factory
### 建造者模式 Builder
### 原型模式 Prototype
## 結構型模式 -- 類or對象組合成更大的結構
### 適配器模式 Adapter
### 代理模式 Proxy
#### 靜態代理
#### 動態代理
### 裝飾模式 Decorator
### 組合模式 Composite
### 外觀模式 Facade Pattern
### 橋接模式 Bridge Patern
### 享元模式 Flyweight Pattern
## 行為型模式 -- 類or對象之間的動作
### 觀察者模式 Observer
### 策略模式 Strategy
### 迭代器模式 Iterator
### 命令模式 Command
### 模板方法模式 Template
### 狀態模式 State
### 職責鏈模式 Chain of Responsibility
### 中介者模式 Mediator
### 備忘錄模式 Memento
### 解釋器模式 Interpreter
### 訪問者模式 Visitor
```


https://zhuanlan.zhihu.com/p/380570323

### 為什麼要使用Design Pattern?

Design Pattern為一些專家，歷經無數的錯誤及試驗而得到的結果。

我們舉一個例子，小學我們都學過如何把1加到100。我們可以怎麼做？？

方法一：土法煉鋼直接從頭加

> 1+2+3...+100

方法二：已知的數學公式

> n(n+1)/2

很明顯，方法二已經有一個“公式”可以幫助我們快速的解決問題，不但簡化過程也節省了時間。
但只是節省過程與時間嗎？？

我們把問題再做延伸，假設今天需要更改成相加1000個數字，那我們該怎麼辦？？

方法一依舊要從1加到1000，但方法二只需要把n改成1000。

這樣的差距，就很像我們在程式開發過程中，突然有需要做變更或是新增需求，如果有使用合適的design pattern，便可輕鬆解決很複雜的問題。

所以使用Design Pattern目的，除了建立良好的軟體系統外，不管在未來維護程式或是新增需求，都可以大大節省我們的時間及精力。

引用 https://ithelp.ithome.com.tw/articles/10234830

## 建立型模式 
在軟體工程中，建立型模式是處理對象建立的設計模式，試圖根據實際情況使用合適的方式建立對象，因為基本的對象建立方式可能會導致設計上的問題，或增加設計的複雜度。建立型模式的關注點是如何建立對象，其核心思想是要把對象的建立和使用相分離。

建立型模式由兩個主導思想構成。一是將系統使用的具體類封裝起來，二是隱藏這些具體類別的實例建立的方式。

建立型模式又分為對象建立型模式和類建立型模式。對象建立型模式處理對象的建立，類建立型模式處理類的建立。詳細地說，對象建立型模式把對象建立的一部分推遲到另一個對象中，而類建立型模式將它對象的建立推遲到子類中。

使用模式我們希望達到不自己創建物件的效果(在程式碼中不使用new)，把創建的過程封裝起來，從而達到單一實例、提升效能、容易擴充···等等的好處

建立型設計模式的一些例子如下：
[工廠方法模式](#工廠方法模式-Factory-Method-Pattern)
[單例模式](#單例模式（Singleton-Pattern）)
[建構者模式](#建構者模式-Builder-Pattern)


## 結構型模式
跟將物件組合成更大的結構有關的模式，歸類為結構型模式
1.轉接器模式 ( Adapter Pattern )
將一個類別的介面轉換為客戶希望的另一個介面。使得原本由於介面不相容而不能一起工作的那些類別可以一起工作。

雖然本來的物件、方法不適合現在使用，但希望建立一個可以重用這個類別的機制，讓這個類別跟其他類別一起共同工作。
![](https://hackmd.io/_uploads/r13wJNdkT.png)

2.橋接模式 ( Bridge Patern )
將抽象的部分和他的實現部分分離，使他們都可以獨立的變化。

代替繼承的關係從而使用組合的關係，像是在借用別人所實踐出的方法，使這兩者可以各自獨立實現其獨立的變化。
![](https://hackmd.io/_uploads/SkcOkNuJT.png)
範例:
一個頁面需要呈現各種不同商品，但是頁面上又需要有不同的頁面，例如只呈現簡單資訊的頁面和詳細資訊的頁面，要把這些不同的資訊串接起來···
定義頁面的Super Class

```java
public abstract class View {
    Resources resources;

    public void setResources(Resources resources){
        this.resources = resources;
    }
    
    //    定義畫面如何擺放
    public abstract void show();
}
```

定義來源的介面

```java
public interface Resources {

    public void photo();

    public void snippet();

    public void describe();
}
```

書本：

    public class Book implements Resources {
    @Override
    public void photo() {
        System.out.println("書本的照片");
    }
    @Override
    public void snippet() {
        System.out.println("書本的簡短說明");
    }

    @Override
    public void describe() {
        System.out.println("書本詳細說明");
    }
    }

包包：

```java
    public class Bag implements Resources {
    @Override
    public void photo() {
        System.out.println("包包的照片");
    }
    @Override
    public void snippet() {
        System.out.println("包包的簡短說明");
    }

    @Override
    public void describe() {
        System.out.println("包包詳細說明");
    }
```

小資訊的頁面根所有資訊的頁面

小資訊

```java
public class FewView extends View{
    @Override
    public void show() {
        resources.photo();
        resources.snippet();
    }
}
```

所有資訊

```java
public class FullView extends View {
    @Override
    public void show() {
        resources.photo();
        resources.describe();
    }
}
```
測試一下

```
        public class Test {
      @org.junit.jupiter.api.Test
      public void test(){   
        FewView fewView = new FewView();
        System.out.println("---- 簡單包包說明 ----");
        fewView.setResources(new Bag());
        fewView.show();
        System.out.println("---- 簡單書本說明 ----");
        fewView.setResources(new Book());
        fewView.show();

        FullView fullView = new FullView();
        System.out.println("---- 詳細包包說明 ----");
        fullView.setResources(new Bag());
        fullView.show();
        System.out.println("---- 詳細書本說明 ----");
        fullView.setResources(new Book());
        fullView.show();

    }
}
```

> 結果:
> ---- 簡單包包說明 ----
> 包包的照片
> 包包的簡短說明
> ---- 簡單書本說明 ----
> 書本的照片
> 書本的簡短說明
> ---- 詳細包包說明 ----
> 包包的照片
> 包包詳細說明
> ---- 詳細書本說明 ----
> 書本的照片
> 書本詳細說明

3.組合模式 ( Composite Pattern )
將物件組合成樹形結構以表示「部分-整體」結構，組合模式使得用戶對單個物件和組合物件的使用具有一致性。

適合用來表示一種不論是個體，或是組合起來一個部分(整體)，都需要做一些相同的運算(工作)的模式，例如公司(團體)的組織。

動態的添加職責像是在事後(程式碼中)才定義各個在基本之外需要具備的其他功能(在android中有關於view的實踐是使用這種方式)。
![](https://hackmd.io/_uploads/SyttyEuJp.png)

4.裝飾模式 ( Decorator Pattern )
動態的給一個物件添加一下額外的職責。就增加功能性來說，裝飾模式比產生子類別更加靈活。

組合模式是一種樹狀的結構，而裝飾模式像是將一個Component經過各個Decorator包裹起來，核心是Component、而Decorator像是糖果或是巧克力一般一層一層包裹的結構。
![](https://hackmd.io/_uploads/r1pc1EO16.png)

5.外觀模式 ( Facade Pattern )
為子系統中的一組介面提供一致的介面，外觀模式定義了一個高層介面，這個介面使得這一子系統更加容易使用。

常常會是重構過程中第一步驟所做的模式。為子系統引入了這個單一的屏障，讓程式碼更容易被理解而且依賴關係較小。
![](https://hackmd.io/_uploads/S15jy4O16.png)

6.享元模式 ( Flyweight Pattern )
為運用共同的技術有效地支援大量細粒度的物件。

最早期的應用有各個字元(文字)的顯示···等等，為了避免佔用資源過多，透過相同物件共享的機制增加效能
![](https://hackmd.io/_uploads/SkXaJEuJT.png)

7.代理模式 ( Proxy Pattern )
為其他物件提供一種代理以控制對這個物件的存取。

單一另一個物件的代理人。
![](https://hackmd.io/_uploads/rJx0kEuk6.png)

## 行為型模式
行為型模式（Behavioral Patterns）是一組設計模式，用於描述物件之間的職責分配和協作，以及物件如何互動和傳遞訊息。這些模式關注的是物件之間的通訊、職責分配和控制流程。行為型模式有助於實現更靈活、可維護和可擴展的程式碼。

一些例子如下：
[觀察者模式](#觀察者模式--Observer-Pattern-)
## 併發型模式
解決多執行緒和併發程式設計中的各種問題和挑戰。這些模式旨在幫助開發人員編寫線程安全的程式碼，避免競態條件、死鎖、活鎖等併發問題。

一些例子如下：
讀寫鎖

## 單例模式（Singleton Pattern）
主要目標是確保一個類別只有一個實例，並提供全域訪問點，以便在整個應用程式中可以方便地訪問該實例。單例模式通常在需要控制某個資源的訪問時使用。

* **私有建構函數**：單例類別的建構函數必須是私有的，以防止外部程式碼通過建構函數創建多個實例。
* **靜態實例變數**：單例類別通常包含一個私有靜態成員變數，用於存儲該類別的唯一實例。
* **公共靜態方法**：單例類別提供一個公共的靜態方法，允許外部程式碼獲取該類別的唯一實例。這個方法通常稱為 getInstance()。
* **延遲初始化**：單例模式可以採用延遲初始化的方式，在第一次訪問時創建實例，而不是在類別加載時就創建實例。


```public class Singleton {
    private static volatile Singleton instance = null;

    private Singleton() {
        // 初始化操作
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

```

```public class Main {
    public static void main(String[] args) {
        // 獲取單例實例
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        // 判斷是否為同一實例
        if (singleton1 == singleton2) {
            System.out.println("singleton1 和 singleton2 是同一個實例");
        }
    }
}

```

### 單例模式（Singleton Pattern）通常在以下情況下非常有用:

1. **資源共享**：當應用程式需要共享資源，如資料庫連接池、執行緒池、日誌記錄器或配置管理器時，可以使用單例模式確保僅有一個實例來管理這些資源，以避免資源競爭和浪費。
2. **全域對象**：當需要在整個應用程式中共享某個對象的狀態或功能時，可以使用單例模式來建立該對象的唯一實例。例如，遊戲中的全域狀態管理器或應用程式的全域設定。
3. **節省資源**：某些對象的建立和初始化可能需要大量的時間和資源，因此希望盡量減少建立這些對象的次數。使用單例模式可以在需要時才建立實例，而不是在應用程式啟動時就建立。
4. **限制實例數量**：在某些情況下，需要限制一個類別的實例數量，例如，執行緒池可能需要限制可以同時執行的執行緒數量，可以使用單例模式來管理這些執行緒。
5. **日誌記錄器**：在應用程式中記錄日誌是一個常見需求。使用單例模式可以確保只有一個日誌記錄器實例，以便在不同部分的程式碼中記錄一致的日誌訊息。
6. **快取管理**：如果需要實現一個快取，可以使用單例模式來管理快取對象，以確保只有一個快取實例用於儲存和檢索資料。
7. **控制訪問點**：單例模式可以用於建立一個全域訪問點，以便在整個應用程式中訪問特定功能或狀態。這有助於提供統一的介面，而無需直接建立類別的實例。



## 工廠方法模式 (Factory Method Pattern)


工廠方法模式( Factory Method )，定義一個用於建立物品的介面，讓子類決定實體化哪一個類別。工廠方法使一個類別的實例化延遲到其子類別。
-- 大話設計模式 p.105

工廠方法模式類別之間的關係像是下面這樣
* Creator：創造者經由FactoryMethod創造產品
* Product：被創造的產品類別
![](https://hackmd.io/_uploads/HkYYpmuJp.png)

EX：
假設我們去速食店買無鹽的薯條
首先我們要有一個商品和工廠的介面...
```java
public interface Product {
    //敘述自己是什麼商品
    public void describe();
}
public interface Factory {
    //工廠返回商品
    public Product getProduct();
}
```
```java
//薯條
public class FrenchFries implements Product{

    //預設有鹽巴的
    String state = "有鹽巴";
    //預設的建構
    protected FrenchFries(){}
    //帶入狀態的建構
    protected FrenchFries(String state){
        this.state = state;
    }

    @Override
    public void describe() {
        System.out.println("我是"+ state +"薯條");
    }
}
```

```java
//薯條工廠
public class FrenchFriesFactory implements Factory {

    //返回一般的薯條
    @Override
    public Product getProduct() {
        return new FrenchFries();
    }

    //返回我們想要的狀態的薯條..
    public Product getProduct(String state) {
        return new FrenchFries(state);
    }
}
```

```java
//嘗試調用薯條工廠做出顧客想要的薯條，成功做出顧客想要的薯條
Factory friesFac = new FrenchFriesFactory();
Product fries = friesFac.getProduct();
Product myfries = ((FrenchFriesFactory) friesFac).getProduct("無鹽的");

fries.describe();//我是有鹽巴薯條
myfries.describe();//我是無鹽的薯條
```

藉由工廠模式，
我們可以在調用的時候才決定我們想要的物品狀態，
在商品中加入大中小包等等的參數，
我們可以決定要哪種份量的商品，
甚至可以決定我們要幾根薯條，
用方法或是各種方式把物件的創造包裝起來，
工廠模式的實現方式很多，
但工廠有個重點會返回我們想要的商品，
掌握這個重點碰到類似的創建模式相信都可以很快掌握喔！


## 建構者模式 (Builder Pattern)
@Vincentl92 

### Builder模式的定義
以下是維基百科上建構者模式的定義
```!
The Builder is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation. It is one of the Gang of Four design patterns.
```
簡單的翻譯一下，
建構者模式是設計來提供一個有彈性解決方案，用OOP的方式來解決一個不同(複雜)物件的創造。目的是為了要分離一個複雜物品的建造和表示建造的方式。

一個物品在建造完成的過程中，需要組成需要設定過多的元件，或裝配過程是有順序的，可以在一一設定完所需要的元件後再產生我們所需要的物件。主要的角色有建造者、指揮者和產品，指揮者控制建造的過程，並且可以用來區隔用戶和建造過程的關聯性。
![](https://hackmd.io/_uploads/BJjJJ4dyT.png)

### 建構者模式的優點
1. 更好的可讀性： 建造者模式可以提高代碼的可讀性，因為它使代碼更具表達性。通過連續的方法調用，可以清晰地看到對象的構建過程。
1. 參數可選性： 建造者模式允許您設置對象的某些參數，而忽略其他參數。這樣可以輕鬆地創建不同配置的對象，而無需使用多個重載構造函數。
1. 避免重複代碼： 建造者模式可以避免在代碼中重複相似的創建邏輯，因為創建過程被封裝在建造者中，可以在多個地方重複使用。
1. 更好的可擴展性： 如果需要添加新的屬性或配置選項，只需擴展建造者而不需要修改客戶端代碼，這提高了代碼的可維護性。
1. 創建不可變對象： 建造者模式通常用於創建不可變對象，這些對象的狀態在創建後不能被修改，這有助於確保對象的一致性和安全性。
1. 具有複雜構建邏輯： 當創建對象的構建邏輯比較複雜，或者涉及多個步驟時，建造者模式特別有用。它可以將這些步驟分解為簡單的方法調用。
1. 改進代碼可測試性： 建造者模式使測試更容易，因為您可以創建偽造的建造者來創建測試對象，並設置所需的屬性。

### 範例
建構MacBook Pro 是一個複雜的過程，元件非常多，有各種規格可以客製化，也有分高規格跟低規格版，我們試著用builder pattern實現建造的過程。

```Java
public class MacbookPro {

    private Processor processor;
    private Memory memory;
    private Storage storage;
    private Graphics graphics;
    private Keyboard keyboard;

    MacbookPro(){}

    public void setProcessor(Processor processor) {
        this.processor = processor;
    }

    public void setMemory(Memory memory) {
        this.memory = memory;
    }

    public void setStorage(Storage storage) {
        this.storage = storage;
    }

    public void setGraphics(Graphics graphics) {
        this.graphics = graphics;
    }

    public void setKeyboard(Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    public Processor getProcessor() {
        return processor;
    }

    public Memory getMemory() {
        return memory;
    }

    public Storage getStorage() {
        return storage;
    }

    public Graphics getGraphics() {
        return graphics;
    }

    public Keyboard getKeyboard() {
        return keyboard;
    }

    @Override
    public String toString() {
        return "{ Macbook : " + "\n" +
                "Processor : " + this.getProcessor().name + "\n" +
                "Memory size : " + this.getMemory().size + "GB" + "\n" +
                "Graphics : " + this.getGraphics().name + "\n" +
                "Storage size : " + this.getStorage().size + "GB" +"\n" +
                "Keyboard language : "+ this.getKeyboard().language +
                " }";
    }

    public static class Processor{
        String name;
        Processor(String name){
            this.name = name;
        }
    }

    public static class Memory{
        int size;
        Memory(int size){
            this.size = size;
        }
    }

    public static class Graphics{
        String name;
        Graphics(String name){
            this.name = name;
        }
    }

    public static class Storage{

        int size;

        Storage(int size){
            this.size = size;
        }

    }
    public static class Keyboard{
        String language;
        Keyboard(String language){
            this.language = language;
        }
    }
}
```
MacbookBuilder介面類別
```Java
Public abstract class MacbookProBuilder {

    protected MacbookPro macbookPro;

    MacbookProBuilder(){
        macbookPro = new MacbookPro();
    }

    abstract MacbookProBuilder buildCPU(MacbookPro.Processor processor);

    abstract MacbookProBuilder buildMemory(MacbookPro.Memory size);

    abstract MacbookProBuilder buildGraphics(MacbookPro.Graphics name);

    abstract MacbookProBuilder buildStorage(MacbookPro.Storage size);

    abstract MacbookProBuilder buildKeyboard(MacbookPro.Keyboard language);

    MacbookPro build(){
        return macbookPro;
    }
}
```
實際的Builder
```Java
Public class MacbookPro_2018 extends MacbookProBuilder {
    @Override
    MacbookPro build() {
        return super.build();
    }

    MacbookPro_2018() {
        super();
    }

    @Override
    MacbookProBuilder buildCPU(MacbookPro.Processor processor) {
        this.macbookPro.setProcessor(processor);
        return this;
    }

    @Override
    MacbookProBuilder buildMemory(MacbookPro.Memory size) {
        this.macbookPro.setMemory(size);
        return this;
    }

    @Override
    MacbookProBuilder buildGraphics(MacbookPro.Graphics name) {
        this.macbookPro.setGraphics(name);
        return this;
    }

    @Override
    MacbookProBuilder buildStorage(MacbookPro.Storage size) {
        this.macbookPro.setStorage(size);
        return this;
    }

    @Override
    MacbookProBuilder buildKeyboard(MacbookPro.Keyboard language) {
        this.macbookPro.setKeyboard(language);
        return this;
    }
}
```
賣macbook的經銷商，只有兩種固定規格的macbook
```Java
public class MacBookSeller {

    private MacbookProBuilder macbookProBuilder;

    MacBookSeller(MacbookProBuilder macbookProBuilder){

        this.macbookProBuilder = macbookProBuilder;
    }


    public MacbookPro lowSpec(){
        return macbookProBuilder
                .buildCPU(new MacbookPro.Processor("2.2GHz 6 核心第八代 Intel Core i7 處理器"))
                .buildMemory(new MacbookPro.Memory(16))
                .buildGraphics(new MacbookPro.Graphics("Radeon Pro 555X 配備 4GB GDDR5 記憶體"))
                .buildStorage(new MacbookPro.Storage(256))
                .buildKeyboard(new MacbookPro.Keyboard("中文注音"))
                .build();
    }

    public MacbookPro highSpec(){
        return macbookProBuilder
                .buildCPU(new MacbookPro.Processor("2.6GHz 6 核心第八代 Intel Core i7 處理器"))
                .buildMemory(new MacbookPro.Memory(16))
                .buildGraphics(new MacbookPro.Graphics("Radeon Pro 560X 配備 4GB GDDR5 記憶體"))
                .buildStorage(new MacbookPro.Storage(512))
                .buildKeyboard(new MacbookPro.Keyboard("中文注音"))
                .build();
    }

}
```
測試
```java
public class Test {
    @org.junit.jupiter.api.Test
    public void test(){

        MacbookPro_2018 macbookPro_2018 = new MacbookPro_2018();

        MacBookSeller macBookSeller = new MacBookSeller(macbookPro_2018);

        //經銷商的固定規格
        MacbookPro myMacbook= macBookSeller.lowSpec();

        System.out.println(myMacbook.toString());

        //想要夢想中的macbook pro需要自己訂製
        MacbookPro dreamMacbook = macbookPro_2018
                .buildCPU(new MacbookPro.Processor("2.9GHz 6 核心第八代 Intel Core i9 處理器"))
                .buildMemory(new MacbookPro.Memory(32))
                .buildStorage(new MacbookPro.Storage(4096))
                .buildKeyboard(new MacbookPro.Keyboard("英文"))
                .buildGraphics(new MacbookPro.Graphics("Radeon Pro 560X 配備 4GB GDDR5 記憶體"))
                .build();

        System.out.println(dreamMacbook.toString());

    }
}
```
結果
```
{ Macbook : 
Processor : 2.2GHz 6 核心第八代 Intel Core i7 處理器
Memory size : 16GB
Graphics : Radeon Pro 555X 配備 4GB GDDR5 記憶體
Storage size : 256GB
Keyboard language : 中文注音 }
{ Macbook : 
Processor : 2.9GHz 6 核心第八代 Intel Core i9 處理器
Memory size : 32GB
Graphics : Radeon Pro 560X 配備 4GB GDDR5 記憶體
Storage size : 4096GB
Keyboard language : 英文 }
```
## 觀察者模式 ( Observer Pattern )

Chris

### 定義：
觀察者模式是一種一對多的依賴關係，當物件的狀態改變，所有依賴於它的物件都會得到通知並被自動更新。

### 例子:
假設有學生訂閱了廣播，每一段時間會換節目。

觀察者和被觀察者的介面
```java
public interface IObserverable {
    public void add(IObserver observer);
    public void remove(IObserver observer);
    public void notifyObservers();
}

public interface IObserver {
    public void update();
}
```

實體的廣播
```java
import java.util.ArrayList;
import java.util.List;

public class PodcastA implements IObserverable {

    List<IObserver> list = new ArrayList<>();

    //節目名稱
    String name = "英文廣播";

    @Override
    public void add(IObserver observer) {
        list.add(observer);
    }

    @Override
    public void remove(IObserver observer) {
        list.remove(observer);
    }

    public String getName() {
        return this.name;
    }

    @Override
    public void notifyObservers() {

        for (IObserver o: list) {
            o.update();
        }
    }

}
```

實體的學生
```java
public class Student implements IObserver {

    IObserverable observerable;

    public Student(IObserverable observerable){
        this.observerable = observerable;
    }

    @Override
    public void update() {
        System.out.println("聽了" + observerable.getName());
    }

}
```

測試
```java
public class Test {
    @org.junit.jupiter.api.Test
    public void test(){
        IObserverable podcast = new PodcastA();
        IObserver student = new Student(podcast);
        podcast.add(student);

        //預設節目是英文廣播
        podcast.notifyObservers();

        //節目變為今年流行歌
        ((PodcastA) podcast).name = "今年流行歌";

        podcast.notifyObservers();
    }
}
```

結果
```
聽了英文廣播
聽了今年流行歌
```



## Adapter
Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.

![](https://hackmd.io/_uploads/BJaskEOya.png)

```
package com.journaldev.design.adapter;

public class Volt {

	private int volts;
	
	public Volt(int v){
		this.volts=v;
	}

	public int getVolts() {
		return volts;
	}

	public void setVolts(int volts) {
		this.volts = volts;
	}
	
}


package com.journaldev.design.adapter;

public class Socket {

	public Volt getVolt(){
		return new Volt(120);
	}
}
```

shen

@Danny
## 外觀模式 ( Facade Pattern )

是一種封裝的應用，將各種系統和類別等等雜亂或是困難的函數式封裝起來，成為一個容易使用和理解的介面，Client端只要調用此一介面就可以實踐想要的功能，而不用理會背後的邏輯。
![](https://hackmd.io/_uploads/rJYQ1N_kT.png)

```
public class SubClassOne {
    public void MethodOne(){
        System.out.println(1);
    }
}

public class SubClassTwo {
    public void MethodTwo(){
        System.out.println(2);
    }
}

public class SubClassThree {
    public void MethodThree(){
        System.out.println(3);
    }
}

public class ClassOne {
    public void MethodFour(){
        System.out.println(4);
    }
}
```
 Facade Class

```
public class Facade {
    private SubClassOne one;
    private SubClassTwo two;
    private SubClassThree three;
    private ClassOne four;

    public Facade(){
        one = new SubClassOne();
        two = new SubClassTwo();
        three = new SubClassThree();
        four = new ClassOne();
    }

    public void MethodA(){
        four.MethodFour();
        one.MethodOne();
    }

    public void MethodB(){
        two.MethodTwo();
        three.MethodThree();
    }

}
```
Test
```
public class Test {
    @org.junit.jupiter.api.Test
    public void test(){

        Facade facade = new Facade();

        System.out.println("MethodA : ");
        facade.MethodA();

        System.out.println("MethodB : ");
        facade.MethodB();

    }
}
MethodA : 
4
1
MethodB : 
2
3
```


## Iterator pattern
@D5k22DL6TsqCosjRchaFYg ENSEAN 
### 目的
了解 forEach() 的來由。

### 說明
簡單來說，實作任意資料結構的 forEach()，最常見的莫過於 Array、List 等，其他像是 Linked List、Stack、Queue、Tree 等也是可實作的資料結構，在模式內負責儲存的物件稱作 Aggregate。

```java
// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 具體迭代器
class ConcreteIterator implements Iterator {
    private int index = 0;
    private String[] elements;

    public ConcreteIterator(String[] elements) {
        this.elements = elements;
    }

    public boolean hasNext() {
        return index < elements.length;
    }

    public Object next() {
        return elements[index++];
    }
}

// 聚合物件接口
interface Aggregate {
    Iterator createIterator();
}

// 具體聚合物件
class ConcreteAggregate implements Aggregate {
    private String[] elements;

    public ConcreteAggregate(String[] elements) {
        this.elements = elements;
    }

    public Iterator createIterator() {
        return new ConcreteIterator(elements);
    }
}

// 使用範例
public class Main {
    public static void main(String[] args) {
        String[] elements = {"A", "B", "C", "D", "E"};
        Aggregate aggregate = new ConcreteAggregate(elements);
        Iterator iterator = aggregate.createIterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}
```

總結
Iterator 模式可說是歷史的軌跡，1994 年的時候，forEach() 的概念尚未成為許多程式語言的內建語法，因此需要特地開一個模式教導他人如何實作。時光飛逝，forEach() 的概念已經變成許多語言的內建語法


## 額外討論

### PureMVC

https://puremvc.org/

![](https://hackmd.io/_uploads/r15-rVdkT.png)


### 推薦
https://refactoring.guru/design-patterns
https://www.tenlong.com.tw/products/9789572054116

