---
# System prepended metadata

title: Clean Code - Ch11 系統
tags: [Clean Code, Book]

---

# Clean Code - Ch11 系統
作者用城市比喻系統，城市如同系統有很多區域，每個區域有各自的功能，並依據這些來進行抽象化和模組化。

## 1. 將所有關注的事分離開來
建立城市時，會用到很多工程車或器具之類的，但這些東西在城市蓋完之後就會被移除乾淨。
**建造** 與 **使用** 應該要分開，如同蓋城市與住城市是兩件不同的事情。
大部分的代碼卻沒有把兩件事情分開，書上以 **延遲初始 / 延遲賦值 (Lazy Initialization / Lazy Evaluation)** 為例。

**延遲初始 / 延遲賦值 (Lazy Initialization / Lazy Evaluation)：** 物件的建立會延後到第一次使用該物件時，好處就是該物件不會被建立，而造成額外的負擔，包括啟動的時間可以比較短。
``` csharp
public Service getService()
{
    if (service == null)
    {
        service = new MyServiceImpl(...); //Good enough default for most cases?
    }
    return service;
}
```
但這樣在測試時會出現一個問題就是必須在單元測試代碼跑到那個部分之前就先將其偽造。而因為這段代碼同時做了 **建立物件** 及 **處理流程** 的部分，因此這邊違反 **單一職責原則**。

而且因為Service參數是一個全域變數，我們也不能確定我們這樣到底會不會影響到其他的東西

## 2. 將建造和使用分離
這邊講的是如何把關注點拆分出來，下面是書上介紹的幾種方法：
#### 1. 把建立物件的動作全部搬到 main function 裡面：
``` csharp
public class MyApp
{
    public static DoSomething(MyBuilder builder,SomeConfig config)
    {
        //應用程式對建造config一無所知，
        //在這單純期望所有事情都已經被順利完成
    }

    public void main()
    {
        var builder = new MyBuilder(); //1: build
        var config = new SomeConfig();//1.1: create
        this.DoSomething(builder, config); //2: run
    }
}

public class SomeConfig
{
    //...
}

public class MyBuilder
{
    //...
}
```

#### 2. 工廠：
上面的方法是建立好物件當做參數傳給應用程式。但有時候類別內部需負責要產生物件，此時可用工廠模式。
``` csharp
public interface ItemFactory
{
    public void makeItem();
}

public class ItemImpl : ItemFactory
{
    public Item makeItem()
    {
        var item = new Item();
        //...
        retrun item;
    }
}

public class Item
{
    //...
}

public class MyApp
{
    protected static void ProcessOrder(ItemFactory itemFactory)
    {
        /*
        這裡的應用程式可以決定何時建造Item，但怎麼建造的細節交付給ItemFactory處理，
        而lineItemFactory與主函式main同屬一側。
        */
        var item = itemFactory.makeItem();
        //Order.add(Item);
        //...
    }

    public void main()
    {
        ItemFactory itemFactory = new ItemImpl();
        ProcessOrder(itemFactory);
    }
}
```
#### 3. 依賴注入 (Dependency Injection，DI)：
透過 DI 甚至可以在 XML 等配置裡面自行設置Interface跟Implement的配對
IoC的意思是控制翻轉。傳統的方法屬於**從上到下**，而interface則是由new()他的類別來決定實作，因此控制的流程翻轉了，不再是從上到下了。
[DI 1](https://www.huanlintalk.com/2011/10/dependency-injection-1.html)
[DI 2](https://www.huanlintalk.com/2011/10/dependency-injection-2.html)

#### 4. 擴大
小城市起初在興建的時候不會考慮到以後會不會變成大城市，同樣的情況小程式起初不會考慮未來會不會變成大程式。
保持適當的關注點分離，軟體系統的架構就能夠遞增地成長。
簡單來說就是要想辦法降低軟體與軟體之間的相依性，軟體才可以擴展與重複使用。

#### 5. 橫切關注點
透過AOP的機制把代碼抽出來，並在需要的時候才加入
AOP感覺比較像是每個class都寫成一樣的格式(ex. 輸入、輸出...)，並且可以重複共用
[AOP](https://openhome.cc/Gossip/SpringGossip/AOPConcept.html)

###### tags: `Clean Code` `Book`