面向对象编程/"状态"是邪恶的!
外观
< 面向对象编程
我们没有足够强调的一点是:状态(与变化相反)是邪恶的!或者,(也许说更准确)维护不必要的状态是所有(呃……许多)错误的根源。让我们看一个例子,现在在 Ruby 中
我们正在显示一个随时间推移的东西,所以我们正在处理像素和秒。根据缩放级别,它们之间存在关联:每秒像素数,或 PPS。
class Timeline
{
PPS;
current_position_in_seconds;
current_position_in_pixels;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s) {current_position_in_seconds = s;} # oops, we're out of sync
GetPosInPixels() {current_position_in_pixels;}
SetPosInPixels(p) {current_position_in_pixels = p;} # oops, we're out of sync
}
在这个例子中,我们正在维护不必要的 state - 也就是说,我们正在用秒和像素来保存位置。这很方便,对于这个类的用户来说也很重要,但我们在这里搞砸了封装。无论何时你设置一个单位的值,你都会破坏另一个单位的正确性。好吧,你说,这里有一个简单的解决方法
class Timeline
{
PPS;
current_position_in_seconds;
current_position_in_pixels;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s)
{
current_position_in_seconds = s;
current_position_in_pixels = s*PPS;
}
GetPosInPixels() {current_position_in_pixels;}
SetPosInPixels(p)
{
current_position_in_pixels = p;
current_position_in_seconds = p/PPS;
}
}
这修复了上一个例子的明显错误,但你给自己带来了很多工作。现在你必须在 Timeline 类中的每个方法中保留每个计算,以保持一致性。可能会有数十个地方会出现这种情况(相信我)。那么当你添加其他单位时,比如英寸怎么办?你必须再次重复所有这些。可以推测,你已经看到了事情的发展方向:计算属性、逻辑属性、虚拟属性,无论你喜欢叫它们什么。让我们再看一遍这个例子
class Timeline
{
PPS; # Pixels Per Second
IPS; # Inches Per Second
current_position_in_seconds;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s) {current_position_in_seconds = s;}
GetPosInPixels() {current_position_in_seconds*PPS;}
SetPosInPixels(p) {current_position_in_seconds = p/PPS; }
GetPosInInches() {current_position_in_seconds*IPS;}
SetPosInInches(i) {current_position_in_seconds = i/IPS; }
}
现在,我们假设 PPS 和 IPS 的转换因子设置正确,为了简化问题,否则我们已经大大简化了问题。现在我们在其他二十个函数中编写,我们只需要关心秒,没有一致性问题要担心。此外,如果我们需要将基本单位从秒更改为像素,Timeline 用户永远不会知道。