面向数据的编程原则
0.1 简介
面向数据的编程是一种编程范式,旨在简化以信息为中心的软件系统的设计和实施。而不是围绕着将数据和代码结合在一起的实体(如实例化的对象)来设计信息系统(例如,从类中实例化的对象) DO鼓励我们将代码与数据分开。此外,DO还提供了关于如何表示和操作数据的指南。
DO的本质是它把数据当作第一等公民。因此,在面向数据的程序中程序中,我们处理数据的方式与我们在其他程序中处理数字或字符串的方式一样简单。
Tip 在面向数据的编程中,数据是第一等公民。
通过坚持三个核心原则,将数据作为一等公民对待是可能的。本章从高层次上介绍了面向数据(DO)编程的核心原则。
面向数据(DO)编程的原则是:
- 将代码与数据分开
- 用通用数据结构表示数据实体
- 数据是不可改变的
当这三个原则结合在一起时,它们形成了一个有凝聚力的整体,如图所示 0.1所示,这使我们能够将数据作为一等公民来对待。因此,我们改善了我们的开发经验,使我们建立的系统更容易理解。
图0.1 面向数据的编程原则
TIP 在面向数据的系统中,代码与数据是分离的,数据由不可变的通用数据结构表示。
重要的是要明白,DO原则是不分语言的。人们可以遵守它们,也可以将它们打破:
- 面向对象语言(OO):JAVA,C#,C++…
- 函数式编程(FP)语言:Clojure, Ocaml, Haskell…
- 同时支持OO和FP的语言:JavaScript, Python, Ruby…
TIP DO原则是与语言无关的。
警告 对于OO开发者来说,过渡到DO可能需要比FP开发者更多的思想转变。
因为DO从一开始就引导我们摆脱将数据封装在有状态类中的习惯。
在本章中,我们将简明扼要地说明这些原则是如何应用于或在JavaScript中被打破。我们选择JavaScript有两个原因。
- JavaScript同时支持FP和OOP
- JavaScript的语法很容易阅读,即使你不熟悉JavaScript,也有可能在高层次上阅读一段JavaScript代码,就像阅读伪代码一样。
我们还将简要地提到,当我们坚持每项原则时,我们的项目会获得哪些好处,以及为了享受这些好处而必须付出的代价。
在这一章中,我们以简单的代码片段为背景说明DO的原则。在全书中,我们将深入探讨如何在生产信息系统的背景下应用DO原则。
0.2 DO原则#1:将代码与数据分开
0.2.1原理简述
原则#1 是一项设计原则,建议将代码和数据明确分开。
NOTE 原则1:将代码与数据分开,代码驻留在函数中,其行为不依赖于在某种程度上被封装在函数上下文中的数据。
这条原则看起来像是函数式编程的原则,但事实上,原则1是与语言无关的。
- 我们可以在FP中打破这一原则,将状态隐藏在一个函数的词法范围内
- 我们可以在OO中坚持这一原则,将代码聚合为静态类的方法
另外,原则#1并不涉及到数据的表示方式。这就是原则#2的主题。
0.2.2 原则1的说明
让我来说明一下,我们如何遵循这个原则,或者在一个处理以下问题的简单程序中打破它:
- 具有firstName、lastName和他/她写了多少本书的Author实体
- 一段计算作者全名的代码
- 一段代码,根据他/她写的书的数量来确定一个作者是否多产。
正如我们前面所写的,原则#1是与语言无关的:人们可以在FP或OOP语言中坚持它或破坏它。
让我们开始对原则#1的探索,首先说明我们如何在OOP中破坏了这一原则。
在OOP中破坏了原则#1
当我们写的代码将数据和代码结合在一个对象中时,我们破坏了OOP中的原则#1,就像清单0.1中那样。
清单0.1 打破OOP中的第一原则
class Author {
constructor(firstName, lastName, books) {
this.firstName = firstName;
this.lastName = lastName;
this.books = books;
}
fullName() {
return this.firstName + " " + this.lastName;
}
isProlific() {
return this.books > 100;
}
}
var obj = new Author("Isaac", "Asimov", 500); // Isaac Asimov wrote 500 books!
obj.fullName();
在FP中破坏了原则#1
我们也可以在没有类的情况下破坏这一原则,以FP的风格,通过编写代码将数据隐藏在函数的词法范围内,如清单0.2所示
清单0.2 在FP中的破坏原则#1
function createAuthorObject(firstName, lastName, books) {
return {
fullName: function() {
return firstName + " " + lastName;
},
isProlific: function() {
return books > 100;
}
};
}
var obj = createAuthorObject("Isaac", "Asimov", 500); // Isaac Asimov wrote 500 books!
obj.fullName();
在FP中遵守原则#1
在看到这个原则如何在OOP和FP中被打破之后,让我们看看我们如何能遵守这个原则。
当我们写代码时,将代码与数据分开,就像清单0.3中那样,我们在FP风格中遵守了这一原则
清单0.3 遵循FP的原则#1
function createAuthorData(firstName, lastName, books) {
return {
firstName: firstName,
lastName: lastName,
books: books
};
}
function fullName(data) {
return data.firstName + " " + data.lastName;
}
function isProlific(data) {
return data.books > 100;
}
var data = createAuthorData("Isaac", "Asimov", 500); // Isaac Asimov wrote 500 books!
fullName(data);
在OOP中遵守原则#1
我们甚至可以通过编写代码来遵守这一原则,即代码放在静态类中,而数据存储在没有函数的类中,如清单0.4。
清单0.4 在OOP中遵守原则#1
class AuthorData {
constructor(firstName, lastName, books) {
this.firstName = firstName;
this.lastName = lastName;
this.books = books;
}
}
class NameCalculation {
static fullName(data) {
return data.firstName + " " + data.lastName;
}
}
class AuthorRating {
static isProlific(data) {
return data.books > 100;
}
}
var data = new AuthorData("Isaac", "Asimov", 500); // Isaac Asimov wrote 500 books!
NameCalculation.fullName(data);
现在我们已经说明了在OOP和FP中如何遵循或打破原则#1,让我们来探讨原则#1给我们的程序带来什么好处。
更多推荐
面向数据编程 Data-Oriented Programming [1]
发布评论