門面模式

門面模式（facade pattern），也翻譯為外觀模式，是軟體工程中常用的一種軟體設計模式，它為子系統中的一組介面提供一個統一的高層介面，使得子系統更容易使用。

## 概述

門面模式是面向對象程序設計中常用的一個設計模式。門面的概念類似於一個建築學中的立面，門面作為一個前端接口來屏蔽更複雜的底層或結構代碼。門面模式可以用來:

- 通用簡化的API屏蔽與更複雜的內部組件和結構, 以提高軟體庫的可讀性和可用性。
- 為更通用的功能提供上下文特定的接口。
- 在廣泛更新重構單層系統或緊密耦合的軟體系統, 提供一個簡化的啟動點，更有利於更多的鬆耦合代碼。

當一個系統非常複雜或難以理解時，開發人員通常會使用門面設計模式，因為該系統有許多相互依賴的類，或者因為其原始碼不可用。門面模式隱藏了更大系統的複雜性，為客戶端提供了一個更簡單的接口。通常會涉及到一個wrapper包含客戶端所需的一組成員的。這些成員代表門面的客戶端訪問系統並隱藏實現細節。

## 結構

Facade：這個門面類為子系統中Packages 1、2、3提供一個共同的對外介面（接口）

Clients：客戶對象通過一個門面介面讀寫子系統中各介面的數據資源。

Packages：客戶可以通過門面介面讀取的內部庫。

## 示例

這是一個抽象的範例。一個客戶「you」通過門面介面「computer」獲取電腦內部複雜的系統資訊。

### C++

下面是C++的例子：

```cpp
import std;

using std::string;
using std::string_view;

class CPU {
private:
    // ...
public:
    void freeze() {
        // ...
    }

    void jump(long position) {
        // ...
    }

    void execute() {
        // ...
    }
};

class HardDrive {
private:
    // ...
public:
    string read(long lba, int size) {
        // ...
    }
};

class Memory {
private:
    // ...
public:
    void load(long position, string_view data) {
        // ...
    }
};

class ComputerFacade {
private:
    CPU cpu;
    Memory memory;
    HardDrive hardDrive;

    const long bootAddress;
    const long bootSector;
    const int sectorSize;
public:
    ComputerFacade(long bootAddress, long bootSector, int sectorSize):
        bootAddress{bootAddress}, bootSector{bootSector}, sectorSize{sectorSize} {}

    void start() {
        cpu.freeze();
        memory.load(bootAddress, hardDrive.read(bootSector, sectorSize));
        cpu.jump(bootAddress);
        cpu.execute();
    }
};

int main(int argc, char* argv[]) {
    ComputerFacade computer(/* parameters here */);
    computer.start();
}
```

### Java

```java
/* Complex parts */
class CPU {
	public void freeze() { ... }
	public void jump(long position) { ... }
	public void execute() { ... }
}

class Memory {
	public void load(long position, byte[] data) {
		...
	}
}

class HardDrive {
	public byte[] read(long lba, int size) {
		...
	}
}

/* Façade */
class Computer {
	public void startComputer() {
		cpu.freeze();
		memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
		cpu.jump(BOOT_ADDRESS);
		cpu.execute();
	}
}

/* Client */
class You {
	public static void main(String[] args) {
		Computer facade = new Computer();
		facade.startComputer();
	}
}
```

### C#

```csharp
// Facade pattern -- Structural example 
using System;

namespace DoFactory.GangOfFour.Facade.Structural {
    // Mainapp test application 
    class MainApp {
        public static void Main() {
            Facade facade = new Facade();
            facade.MethodA();
            facade.MethodB();
            // Wait for user 
            Console.Read();
        }
    }

    // "Subsystem ClassA" 
    class SubSystemOne {
        public void MethodOne() {
            Console.WriteLine(" SubSystemOne Method");
        }
    }

    // Subsystem ClassB" 
    class SubSystemTwo {
        public void MethodTwo() {
            Console.WriteLine(" SubSystemTwo Method");
        }
    }

    // Subsystem ClassC" 
    class SubSystemThree {
        public void MethodThree() {
            Console.WriteLine(" SubSystemThree Method");
        }
    }

    // "Facade" 
    class Facade {
        SubSystemOne one;
        SubSystemTwo two;
        SubSystemThree three;
        public Facade() {
            one = new SubSystemOne();
            two = new SubSystemTwo();
            three = new SubSystemThree();
        }
        public void MethodA() {
            Console.WriteLine("\nMethodA() ---- ");
            one.MethodOne();
            two.MethodTwo();
        }
        public void MethodB() {
            Console.WriteLine("\nMethodB() ---- ");
            two.MethodTwo();
            three.MethodThree();
        }
    }
} 
```

### Python

下面是Python的例子，這裡的類可以放置在不同的模塊或包之中，這裡將如下所有硬體有關的類都保存入當前工作目錄下的文件`hardware.py`之中：

```python
class CPU():
    def freeze(self): pass
    def jump(self, position): pass
    def execute(self): pass

class Memory():
    def load(self, position, data): pass

class HardDrive():
    def read(self, lba, size): pass
```

接著導入這個模塊並使用其中的類：

```python
from hardware import CPU, Memory, HardDrive

class Computer():
    def __init__(self, *, cpu, mem, hd):
        self.cpu = cpu
        self.mem = mem
        self.hd = hd
    def start_computer(self):
        self.cpu.freeze();
		self.mem.load('BOOT_ADDRESS',
		    self.hd.read('BOOT_SECTOR', 'SECTOR_SIZE'))
		self.cpu.jump('BOOT_ADDRESS');
		self.cpu.execute();

facade = Computer(cpu=CPU(), mem=Memory(), hd=HardDrive())
facade.start_computer()
```