關注點分離

计算机科学中一种设计原则

計算機科學中,關注點分離(Separation of concerns,SoC),是將計算機程序分隔為不同部份的設計原則。每一部份會有各自的關注焦點。關注焦點是影響計算機程式程式碼的一組資訊。關注焦點可以像是將程式碼優化過的硬件細節一般,或者像實例化類別的名稱一樣具體。展現關注點分離設計的程序被稱為模組化程序[1]。模組化程度,也就是區分關注焦點,通過將資訊封裝在具有明確界面的程序代碼段落中。封裝是一種資訊隱藏手段[2]。資訊系統中的分層設計是關注點分離的另一個實施例(例如,表示層,業務邏輯層,數據訪問層,持久數據層)[3]

關注點分離,是對只與「特定概念、目標」(關注點英語Concern (computer science))相關聯的軟件組成部分進行「標識、封裝和操縱」的能力,即標識、封裝和操縱關注點的能力。是處理複雜性的一個原則。由於關注點混雜在一起會導致複雜性大大增加,所以能夠把不同的關注點分離開來,分別處理就是處理複雜性的一個原則,一種方法。分離關注點使得解決特定領域問題的程式碼從業務邏輯中獨立出來,業務邏輯的程式碼中不再含有針對特定領域問題程式碼的調用(將針對特定領域問題程式碼抽象化成較少的程式碼,例如將程式碼封裝成function或是class),業務邏輯同特定領域問題的關係通過側面來封裝、維護,這樣原本分散在整個應用程式中的變動就可以很好的管理起來。

關注點分離的價值在於簡化計算機程序的開發和維護。當關注點分開時,各部份可以重複使用,以及獨立開發和更新。具有特殊價值的是能夠稍後改進或修改一段代碼,而無需知道其他部分的細節必須對這些部分進行相應的更改。

實作

編程語言提供的物件導向設計模塊化編程機制,就是允許開發人員提供SoC的機制[4]。例如,C#,C++,Delphi和 Java等物件導向的編程語言可以將關注點分解為物件,像MVCMVP這樣的架構設計模式,將內容從呈現和數據處理(模型)與內容分開(呈現與內容分離)。服務導向英語Service-orientation的設計可將關注點分解為服務英語Service (systems architecture)。諸如C和Pascal之類的程序式編程語言可將關注點分成過程函數面向切面編程語言可以將關注點分解為方面英語Aspect (computer programming)和對象。

在許多其他領域,例如城市規劃建築信息設計,分離關注點也是一個重要的設計原則。目標是更有效地理解,設計和管理許多功能相互依存的複雜系統,以便功能可以重用,獨立於其他功能進行優化,並且避免其他功能的潛在故障。常見的例子包括將一個空間分隔成多個房間,這樣一個房間的活動不會影響其他房間的人;或是配電將爐子保持在一個電路,而燈光則保持在另一個電路上,這樣爐子的超載就不會影響燈光。房間分隔的例子顯示了封裝,其中一個房間內的資訊(無論有多混亂)不會用於其他房間,除非通過界面(門是接口)。電路的例子表明,一個模組內部的活動是一個電力消費者附加的電路,不會影響不同模塊中的活動,因此每個模組不會額外去關注另一個模塊發生的情況。

起源

這個概念是1974年,艾茲赫爾·戴克斯特拉在他的文章《On the role of scientific thought》中提出的[5]

讓我告訴你,對我來說所有聰明的思考的共通特性是什麼。一個人要有系統地深入研究一門課題;必須將這們課題獨立出來,記住在任何時候都只能關注其中一個方面。 比如說,我們知道一個程式必須是正確的,因此我們可以只抓這個點來研究;我們同時也清楚它應當是高效率的,我們可以改天來研究它的效率,等等。我們也可以問自己,程式是否是可取的(desirable)?如果是,為什麼?相反的,同時應對好幾個個方面不會得到任何結果!這就是我有時提到的「the separation of concerns(關注點分離)」。這個技巧就算不是完美可行的,也仍是我知道有效地組織思維的唯一可用技巧。這是就是我說的「將一個人的注意力集中在幾個方面上」。這並不是說忽略其他方面,只是表明從這個方面來看,其他方面並無關緊要這一事實。這即是同時擁有單任務和多任務思維。

15年之後,這個概念已經被人們所接受。1989年,Chris Reade寫的《Elements of Functional Programming》有這樣的描述[6]

一個程式在執行的時候一定會同時做以下幾件事情:

  1. 描述所要解決的問題
  2. 按照計算的順序分成幾個部分執行
  3. 同時處理內存管理

Reade 接着說,

理想情況下,程式設計師應該只關注第一個問題(所要解決的問題),因為這個問題是更應該被關注。很明顯的,我們可以通過解決重要的問題來得到更可靠的結果。

分離關注還有其它的好處。比如,程式可以分離內存管理和執行順序。然後我們只去一步步的解決問題,不管機器的物理架構。當我們用高速平行的機器或者分佈式系統的時候,只需要改動很小的一部分。

這就意味着程式語言的實現者必須在不同的機器和機制下,實現相關的功能。

例子

互聯網協議堆疊

關注點分離是網絡設計中的重點。在TCP/IP協議族的設計時,有許多心力用在關注點分離,因此有良好定義的OSI模型。這可以讓通訊協定的設計者專注在每一層的關注點,不考慮其他層的影響。例如應用層的協定,關注的是如何將郵件資料在可靠的傳送服務上傳輸的細節(一般會是傳輸控制協議),不會關注傳輸控制協議旳細節。TCP不會關注資料封包的路由,路由是由網絡層處理的內容。

HTML,CSS和JavaScript

HTML層疊樣式表(CSS)和JavaScript(JS)是開發網頁及相關服務時會用到的語言,彼此的機能是互補的。HTML主要是用在網站內容的結構、CSS是用在內容呈現方式的定義、JS定義網頁和用戶互動的方式,以及網頁的行為。以往的設計不是如此,在導入CSS之前,HTML同時要定義網頁的內容以及顯示方式。

主題導向的編程

主題導向的編程英語Subject-oriented programming可以用分開的軟件結構來處理關注點分離,每一個關注點之間都是平等的。每一個關注點會有自己的類別結構,這些類別結構組成物件、也會提供狀態和方法給複合各關注點的結果。相依性關係會描述這些不同關注點中類別和方法,彼此之間的關係,讓許多關注點可以聯合產生複合式的行為。多維度關注點分離(Multi-dimensional Separation of Concerns)可以用多維「矩陣」的方式來進行各關注點之間的分析及複合,每一個關注點提供一個維度,上面會列舉各個點,其中的矩陣元素會有適當的軟件工件(software artifacts)。

面向切面的程序設計

面向切面的程序設計可以將橫切關注點視為主要關注點進行處理。例如,大部份旳軟件都需要某程度的安全性數據記錄。安全性及數據記錄一般會視為次要關注點,主要關注點一般是實現業務目標。不過在設計程式時,其安全性需要在一開始就考慮進來,而不是視為次要關注點。若在程式開發後再考慮安全性,多半會有安全模型不足的問題,會有很多後續被攻擊的風險。這可以用面向切面的程序設計來解決。例如,有一個切面可以寫成強制呼叫特定API時一定要記錄,或是在丟出例外時,一定要記錄錯誤,不論哪一段程式的程式碼丟出錯誤或是傳播錯誤,都不會遺漏[7]

人工智能中的分析水準

認知科學人工智能中,常常會用到大衛·馬爾的levels of analysis。研究者可以專注在 (1)需要計算人工智能的哪一個層面 (2)使用的演算法 (3)演算法在硬件中實現的情形。關注點分離類似軟件工程及硬件工程中的介面/實現的差異。

規範化系統

規範化系統(normalized system)中,關注點分離是四個指導原則之一。堅持此一原則可以減少組合性的效應。組合性的效應會在維護軟件時,漸漸的進入系統中。在規範化系統中,可以用工具積極的支持關注點分離。

關注點分離和部份類別

關注點分離可以用部份類別英語partial class的方式實現[8]

關注點分離和Ruby中的部份類別

bear_hunting.rb
class Bear
  def hunt
    forest.select(&:food?)
  end
end
bear_eating.rb
class Bear
  def eat(food)
    raise "#{food} is not edible!" unless food.respond_to? :nutrition_value
    food.nutrition_value
  end
end
bear_hunger.rb
class Bear
  attr_accessor :hunger
  def monitor_hunger
    if hunger > 50
      food = hunt
      hunger -= eat(food)
    end
  end
end

相關條目

參考資料

  1. ^ Laplante, Phillip. What Every Engineer Should Know About Software Engineering. CRC Press. 2007 [2020-12-16]. ISBN 978-0849372285. (原始內容存檔於2021-05-29). 
  2. ^ Mitchell, Dr. R. J. Managing Complexity in Software Engineering. IEE. 1990: 5 [2020-12-16]. ISBN 0863411711. (原始內容存檔於2021-05-31). 
  3. ^ Microsoft Application Architecture Guide. Microsoft Press. 2009 [2020-12-16]. ISBN 978-0-7356-2710-9. (原始內容存檔於2021-05-29). 
  4. ^ Painter, Robert Richard. Software Plans: Multi-Dimensional Fine-Grained Separation of Concerns. Penn State. CiteSeerX 10.1.1.110.9227 . 
  5. ^ Dijkstra, Edsger W. On the role of scientific thought. Selected writings on Computing: A Personal Perspective. New York, NY, USA: Springer-Verlag. 1982: 60–66. ISBN 0-387-90652-5. 
  6. ^ Reade, Chris. Elements of Functional Programming . Boston, MA, USA: Addison-Wesley Longman. 1989. ISBN 0-201-12915-9. 
  7. ^ Jess Nielsen. Building Secure Applications (PDF). June 2006 [2012-02-08]. (原始內容存檔 (PDF)於2016-04-16). 
  8. ^ Tiago Dias. Hyper/Net: MDSoC Support for .NET (PDF). DSOA 2006. October 2006 [2007-09-25]. (原始內容存檔 (PDF)於2016-10-03). 

外部連結