架構演化思考總結(1)

畅知發表於2024-07-23

架構是什麼?

答:架構是對依賴的統一管理。

什麼是依賴?分為幾種?我們為什麼要對它進行管理。

依賴就是持有物件,或者說是持有一個非空的引用。

單向依賴

正如專案開發中,物件和物件之間都會有相互持有、相互呼叫的需求的。而物件間的持有就是一種依賴。A想要完成一個邏輯處理,需要呼叫B的一個方法來實現,那麼我們就可以說A對B產生了依賴。

好,現在A持有了B的引用,可以直接呼叫B的方法,這就構成了單向依賴。

單項依賴是最基本、最常見的一種依賴關係,初次接觸程式設計專案的小同志也比較容易理解和使用單向依賴。但是產生單項依賴也要根據A和B具體的身份層次而確定,正如老子打小子好像天經地義,兒子打老子自然算作“忤逆”。

正常健康的單向依賴關係是父物件持有子物件。

這也比較容易理解,如果子物件持有父物件關係,那麼隨著業務量的增加,父物件的方法邏輯內容會越來越多,子物件若想完成某個處理邏輯直接呼叫父物件的方法來實現,自然會造成頭重腳輕的不健康的狀態。

考慮層級

對於物件間單項依賴合不合理的判斷要看產生依賴關係的兩個物件間的層級關係。

如果是父子關係,那麼原則是父物件持有子物件的依賴較為合適;

如果是兄弟關係,儘量透過共同持有的父物件進行交流。兄弟間相互持有依賴,也會增加維護成本,儘量透過共同持有一個物件方式來進行“交流”。

image

image

也就是說最好的依賴關係就是上級依賴下級,同級別物件之間依賴不推薦,子物件依賴父物件應當避免。

當然這屬於是一種程式設計設計思想,不僅僅侷限於物件和物件之間的依賴關係的實現中,模組與模組中間、層級和層級之間都應遵循上級持有下級的設計準則。

image
遊戲專案也應是遵循表層(高層)對底層依賴。

考慮互動方式

上文內容已經展示出物件之間互動的三種方式:

  • 方法
  • 委託
  • 事件

方法:

父物件持有子物件,直接可以呼叫子物件中的方法,完成互動。

雙向依賴

首先表明:不建議出現雙向依賴。

image

因為相互持有的物件關係間的耦合度過高,不符合我們一貫追求的“低耦合,高內聚”準則,為此我們堅決杜絕雙向依賴關係,不管是父子、兄弟層級之間的,任何形式的雙向依賴關係都不應現。

既然把話說的那麼絕對,那麼需要相互通訊怎麼辦?

這就提到上文中的另外兩種互動方式--委託和事件。

試想一下,典型需要相互溝通的一個例子。

按鈕點選,按鈕控制指令碼A需要檢測使用者的點選、使用者點選之後要告知具體執行的指令碼B。這是A對B有交流需要,假如B的具體操作是播放一個動畫,在動畫播放期間按鈕要失活,防止使用者再次點選,等B的動畫播放完畢了需要B告知A,讓A恢復按鈕狀態並繼續檢測使用者的點選,這是B對A產生的依賴需求。

如果相互持有對方物件,直接呼叫對方的相互方法即可,但是要解耦,自然需要用到委託和事件。

使用委託解耦單向依賴

上文中闡述出單向依賴要符合長輩持有兒孫的原則,那麼兒孫對長輩有通訊需要但不能持有長輩依賴怎麼辦?

這裡使用委託來完成下層對上層的通訊需求。

namespace  DependencyDemo
{

     public class A : MonoBehaviour
    {
        B b;

        void Start()
        {
           b = transform.Find("Animation").GetComponent<B>();

            // 註冊完成的事件
            b.OnDoSomethingDone += ()=>{
                Debug.Log("動畫播放完畢");
            };
        }
    }

    public class B : MonoBehaviour
    {
        // 定義委託
        public Action OnDoSomethingDone = ()=>{};

        //當動畫播放完畢後呼叫
        public void DoSomething()
        {
            //觸發委託中的函式執行
            OnDoSomethingDone();
        }
    }
}

在B中宣告一個委託,待動畫播放完畢之後觸發呼叫委託中的函式。而持有B的A則可以拿到B中的委託,將動畫播放完畢要做的操作函式新增到此委託中,這樣實現了下級B對上級A的通訊,而B並沒有持有A。

那麼使用委託有什麼缺點呢?

委託中註冊函式和登出函式要成對出現!

委託中註冊函式要保證最後登出掉,也就是說註冊和登出要成對出現,以免出現空引用的問題。使用委託應當像使用沒有GC功能的程式語言那樣,申請記憶體使用完畢之後要保證釋放,養成成對的好習慣。

其實不論是委託還是記憶體使用,在程式設計中常常要注意使用的模組、物件的生命週期,例如呼叫某個函式時發現物件沒有例項化,載入資源時候發現資源管理類還未初始化,諸如此類問題,,自然要我們清除的知曉呼叫的物件的生命週期。

委託另一點就是會增加程式碼量,可以想象委託算作一個回撥函式容器,一個函式執行時候要有個對應的回撥,那麼隨著業務量增加,函式增多,對應的委託也相應的增多,而且委託需要相應的宣告,不免也增加了對委託管理的工作量。

至此,本節展示了使用委託來解耦下級對上級依賴。但是同級別之間的單項依賴則不建議使用委託。

自此我們知曉這樣一個原則或者觀念:底部向高層通訊可以使用委託。

相關文章