关注点分离

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

计算机科学中,关注点分离(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). 

外部链接