《Effective Ruby:改善Ruby程序的48条建议》一第14条:通过protected方法共享私有状态

简介:

本节书摘来自华章出版社《Effective Ruby:改善Ruby程序的48条建议》一书中的第2章,第2.9节,作者 [美]彼得 J.琼斯(Peter J. Jones),更多章节内容可以访问云栖社区“华章计算机”公众号查看

第14条:通过protected方法共享私有状态

封装是面向对象编程中的主要准则之一,它是指一个对象的内部实现仅可被内部访问,不可被外部访问。这使得我们可以构建一层壁垒。一方面,暴露那些允许别人使用的外部接口。另一方面,可以灵活地改变其内部的实现而无需为破坏类的外部行为而担忧。在Ruby语言中,这种壁垒可能理论味十足,但至少是存在的。
以实例变量为例——它们默认是私有的。如果不借助任何后门式的元编程技巧,它们只能在实例方法内部被访问。若将其暴露到外部,则需定义被称为accessor的方法。这是个好消息。你可以放心地在实例变量中存储内部状态而无需担心它可能会意外地成为公共接口的一部分。这样的封装在多数情况下都是极好的,但有一种情况它们反而会成为阻碍。因为某些时候一个对象需要访问另一个对象的内部状态。考虑下面的
例子:
image

方法Widget#overlapping?会检查其本身是否和另一个对象在屏幕上重合。Widget类的公共接口并没有将屏幕坐标对外暴露;它们的具体实现隐藏于内部。看上去突破封装的壁垒的唯一方法就是使用一些元编程技巧了。但这种方法有其自身的缺点。
通常情况下,当设计一个具有内部状态的类时,正确的做法是尽可能减少对该状态的直接访问,而是使用最小数量的访问方法。这样做既提升了可测试性也降低了变更可能对系统造成的破坏。把对于状态的操作隐藏于私有方法中也有助于优化程序,如优化内存(参考第48条)。为了提升可维护性,更好的做法是让Widget类的屏幕坐标信息保持私有,即便是对于overlapping?方法也应如此。你可能希望去写一个私有方法来充当访问屏幕坐标的接口,但在这种情况下并不适用。
在Ruby语言中,私有方法的行为和其他面向对象的编程语言中不太相同。Ruby语言仅仅在私有方法上加了一条限制——它们不能被显式接收者调用。无论你在继承体系中的哪一级。只要你没有使用接收者,你都可以调用祖先中的私有方法。但是你不能调用另一个对象的私有方法,即便是调用者和接收者隶属于同一个类。如果你使用一个私有方法来访问屏幕坐标,你仍然无法在overlapping?方法中使用它们。还好,Ruby提供了针对这种情况的解决方式:protected方法。
接收者无法使用私有方法,但可以使用protected方法。但有一个例外,而且它还有些复杂。被接收者调用的方法必须处于调用者继承体系中的哪一级,只要调用者和接收者都可以通过继承体系共享同一个实例方法,那么调用者就可以调用接收者上的方法。调用者和接收者并不需要是同一个类的实例,但是它们必须共享一个定义了该方法的超类。
对于Widget类来说,可以定义一个暴露私有屏幕坐标的方法,但并不通过公共接口来实现。其实现方式是声明该方法为protected,这样我们既保持了原有的封装性,也使得overlapping?方法可以访问其自身以及其他传入的widget实例的坐标。这样就无需元编程的黑魔法了!
image

这正是设计protected方法的原因——在相关类之间共享私有信息。
要点回顾
通过protected方法共享私有状态。
一个对象的protected方法若要被显式接收者调用,除非该对象与接收者是同类对象或其具有相同的定义该protected方法的超类。

相关文章
|
测试技术 C++ Ruby
C++程序中嵌入Ruby脚本系统
Ruby,一种为简单快捷面向对象编程(面向对象程序设计)而创的脚本语言,由日本人松本行弘(まつもとゆきひろ,英译:Yukihiro Matsumoto,外号matz)开发,遵守GPL协议和Ruby License。
1559 0
|
消息中间件 安全 Ruby
Nanite:Ruby程序的一个自我装配集群
本文讲的是Nanite:Ruby程序的一个自我装配集群,Nanite(由Ezra Zygmuntowicz开发)是Engine Yard云计算策略的一个新兵:它是“Ruby程序的一个自我装配集群”,用以构筑高度可伸缩的Web应用的后端。
1096 0
|
程序员 Ruby
《Effective Ruby:改善Ruby程序的48条建议》一导读
学习一门新的编程语言通常需要经过两个阶段。第一阶段是学习这门编程语言的语法和结构。如果我们具有其他编程语言的经验,这个阶段通常只需要很短的时间。以Ruby为例,接触过其他面向对象语言的程序员对Ruby的语法也会比较熟悉。有经验的程序员对于语言的结构(如何根据语法构建应用程序)是很熟悉的。
1207 0
|
NoSQL 数据库 Ruby
我的第一个Ruby On Rails + MongoDB程序
    最近想进一步学习一下MongoDB,而很久之前使用过ROR,正好也凑个机会重新拾起来。下面是建立第一个项目的过程。        主要参考文档:        1. Rails 3 - Getting started        2.
925 0
|
Apache Ruby Windows
让Apache支持ruby写的cgi程序
ruby apache cgi 配置 1,按说明安装ruby的apache mod 2,配置文件如下: 1 ######################################################### 2 # ruby cgi 配置 3 #######...
760 0
|
Ruby
Ruby On Rails学习笔记(3)——Rails程序由0到1
     正如Rails的理念一样,创建一个新的Rails应用程序的过程非常简单,下面就来看看如何从0到1建立一个全新的Rails应用程序。     1、启动InstantRails,打开其Rails应用程序管理器(Rails Application Manager):         2、创建...
743 0
|
2月前
|
Ruby
|
1月前
|
数据采集 Web App开发 数据处理
Ruby网络爬虫教程:从入门到精通下载图片
Ruby网络爬虫教程:从入门到精通下载图片