面向对象和函数式不是对立的。
面向对象语言的分类
- 纯面向对象语言:一切都是对象,包括数字、字符串也是对象,如 Python、Ruby、Scala、Smalltalk
- 完全支持面向对象,也支持过程式,如 Java、C++、C#
- 本来不支持面向对象,后来加上的,如 PHP、Perl
- 看起来像面向对象,但没有完全使用面向对象(比如基于原型来模拟面向对象):JavaScript、Lua
- 其他还有很多种。
设计模式
设计模式指的是对于某个广泛出现的问题提出的适用性广的、可复用的解决方法,也叫套路。
某些面向对象语言内置了一些套路,如单例、事件、工厂等。
对面向对象的批评
- 复用性和模块化并没有达到预期目标。
- 过分强调模型,而忽略了计算和算法。
Smalltalk
双引号是注释,不要使用。
(1 + 2) * 3
'Hello, world' printNl //'Hello, world'
数组
x := Array new: 20 //将一个数组赋值给x 数组的长度是20,默认会打印出20个nil(也就是null)
x at: 1 //获取x里面的第一个(初始化索引就是从1开始)
x at: 1 put: 99 // x在第一个位置放一个99
(x at: 1) + 1 //在x第一个位置的数加1
Set
使用英文句号断句
x := Set new // 赋值给x一个不能重复的数组
x add: 5. x add: 7. x add: 'foo' // 在x里添加5 7 'foo',打印出Set(5 7 'foo')
x remove: 5 // 从x里移除5
x includes: 7 // x里面是否包含7 false不包含,true包含
有一种简写形式,可以少写几次 x
x add: 5; add: 7; add: 'foo'
打印出x
x 或者 x yourself 或者 x printNl
字典
y := Dictionary new // Dictionary()
y at: 'One' put: 1 // 在One中添加一个1 Dictionary('One' -> 1)
y at: 'Two' put: 2
y at: 1 put: 'One'
y at: 2 put: 'Two'
y at: 1 //y在1对应的值 'One'
y at: 'Two'
y
y! 用于删除 y 的值
y
面向对象的核心就是对象与对象之间交互。
- 对象维护自己的状态和生命周期
- 每个对象独立
- 对象和对象直接通过消息传递来工作
函数式也可以做成消息传递风格
消息传递风格使用消息传递风格就可以构造 account 对象了,account 对象可以响应 withdraw(取钱)和 deposit(存钱)消息:
let makeAccount = money => {
let take = (n) => {
money = money - n
return money
}
let save = (n) => {
money = money + n
return money
}
let dispatch = (m) => {
return (
m === 'take' ? take :
m === 'save' ? save :
new Error('unknown request'))
}
return dispatch
}
接下来是使用 makeAccount 创造两个 account 对象(其实是过程):
let account1 = makeAccount(100)
account1('take')(70) // 30
account1('save')(50) // 80
函数式代码示例(Pager组件)
function Pager(props) {
const buttons = Array.apply(null, { length: props.total })
.map((n, index) => index + 1)
.filter(n => {
if (n === 1) {
return true;
} else if (n === props.total) {
return true;
} else if (Math.abs(n - props.current) <= 2) {
return true;
} else {
return false;
}
})
.reduce((prev, n) => {
const last = prev[prev.length - 1];
return prev.concat(n - last > 1 ? [-1, n] : [n]);
}, [])
.map(n => (n === -1 ? <span>...</span> : <button>{n}</button>));
return <div>{buttons}</div>;
}
function App() {
return (
<div className="App">
<Pager current={5} total={10} />
</div>
);
}
在线demo:https://codesandbox.io/s/happy-williams-n80v7
赋值的本质
如果没有赋值,参数和变量只不过就是一个值的名字;
如果有了赋值,参数和变量 就是一个容器,可以保存不同的值。
这带来的问题很多。广泛采用赋值的程序设计叫做『命令式/指令式』程序设计。
命令式程序在遇到『并发』『克隆』等问题时经常很令人头疼。
函数式编程的特点
- 数学!(公理化和可证明)
- 更加强调程序执行的结果而非执行的过程
- 函数是一等公民(函数可以作为参数),高阶函数
- 纯函数,拒绝副作用
- 不可变数据
- 数据即代码,代码即数据
- 引用透明
网友评论