- 貫穿設計模式:用一個電商項目詳解設計模式
- 偉山育琪
- 1353字
- 2024-12-28 11:44:55
1.2.5 迪米特法則
迪米特法則(Law of Demeter,LOD),又叫作最少知識原則(The Least Knowledge Principle),一個類對于其他類知道得越少越好。簡單來說就是只暴露方法入口,而實現細節不需要暴露給調用者。
干澀的文字描述總是不能給讀者帶來清晰的認知,在本書后續項目落地設計模式實戰的“多種類第三方支付”章節,會為大家帶來“策略模式+門面模式+工廠模式+亨元模式”的落地實戰。調用者只需要關心支付類型(如支付寶支付、微信支付等),無須關心具體的支付交互細節,“門面模式”就是一種遵循迪米特法則的、極具代表性的實現。
關于項目實戰落地,我們后續章節細細道來。在這里,我更想和大家聊聊Spring源碼中哪部分的設計是最具代表性的、最能體現遵循迪米特法則的設計。我們先來回憶一下Spring容器使用的簡單示例,代碼如下:

以上代碼是Spring容器使用最為基礎的示例,相信接觸過Spring框架的讀者對此都了然于心。從代碼的書寫過程中可以看到,想要使用Spring框架,我們僅僅關心以下三點即可。
①XML配置文件的創建或者標有@ComponentScan配置類的創建及注解使用。
②ApplicationContext的構造函數及入參。
③getBean方法的使用。
作為Spring框架的使用者,我們僅僅需要知道以上三點就可以了,可是Spring源碼為我們做了很多。以注解容器AnnotationConfigApplicationContext的創建方式為例(注解方式是趨勢,簡單方便,避免對復雜XML配置文件的維護管理),我們來看一下Spring源碼為我們做了什么,先來看容器創建的入口——AnnotationConfigApplicationContext的構造函數,代碼如下:

構造函數很清晰,包含三行代碼,接下來我們分別對這三行函數所包含的內容進行說明。
(1)this()方法。
this()方法調用了無參構造函數,我們來看看無參構造函數做了些什么,代碼如下:

依然是很清晰的邏輯,表面看無非是創建了兩個對象,但是這兩行代碼實際上為我們做了很多重要的底層邏輯,很抱歉不能夠更深層次地進行源碼的展示,但筆者會盡最大可能為大家解釋這兩行代碼所完成的功能,如果你閱讀過Spring源碼必然會產生共鳴,如果你即將要閱讀Spring源碼必然會有所幫助,當然,你最終也會深刻地體會到Spring的這部分源碼設計是如何遵循迪米特法則的。接下來我們來介紹以下這兩行代碼的功能。
①創建讀取Annotation注解下的BeanDefinition閱讀器,為Bean工廠添加比較器依賴,如@Order注解、@Priority注解,為Bean工廠添加延時加載依賴,如@Lazy注解。
②注冊Spring依賴的BeanDefinition,如內部注解配置處理器internal-ConfigurationAnnotationProcessor、內部依賴注入處理器internalAutowiredAnnotatio nProcessor等。
③初始化Spring運行的Environment,如SystemProperties、systemEnvironment。
④基于“初始化子類之前需提前初始化父類”的規則,隱性地在父類GenericApplicationContext的無參構造中初始化Bean工廠核心類——DefaultListableBeanFactory。
⑤創建classPath的包掃描器,為后續自定義的Bean提供掃描功能。
這些都是我們無須關心的,各種Bean對象的讀取、注冊、掃描,甚至運行環境的初始化我們都無須關心。最小知識原則就體現在這里。
(2)register(componentClasses)方法。
我們先來看看該方法的源碼,代碼如下:

我們可以看到,該方法依靠我們在this()方法中創建的reader進行配置類的注冊,最終會通過我們在“依賴倒置原則”所介紹的registerBeanDefinition方法進行BeanDefinition的注冊,此處就不再過多地展開描述。
(3)refresh()方法。
這個方法是Spring容器初始化的核心,這個方法涉及的內容十分豐富,我們來看看它都做了些什么,代碼如下(方法功能介紹請參見注釋):

試想一下,如果Spring沒有為我們做以上的功能,那么監聽器要自己實現,消息處理器要自己實現,事件分發要自己考慮,這將是非常可怕的事情。Spring僅為使用者暴露了有限的、簡單的方法調用入口,而將其他所有的功能隱藏起來,做到了最少知識原則,符合迪米特法則。