A F*_*kly 5 ruby access-modifiers accessor attr-accessor
在Ruby中定义访问器时,简洁(我们都喜欢)和最佳实践之间可能存在紧张关系.
例如,如果我想在实例上公开一个值但禁止任何外部对象更新它,我可以执行以下操作:
class Pancake
attr_reader :has_sauce
def initialize(toppings)
sauces = [:maple, :butterscotch]
@has_sauce = toppings.size != (toppings - sauces).size
...
Run Code Online (Sandbox Code Playgroud)
但突然间我正在使用一个原始实例变量,这让我抽搐了.我的意思是,如果我需要在未来某一日期设定之前处理has_sauce,我可能需要做更多的重构不仅仅是重写访问.来吧,原始实例变量?布莱什.
我可以忽略这个问题并使用它attr_accessor.我的意思是,任何人都可以设置属性,如果他们真的想要; 毕竟,这就是Ruby.但后来我失去了数据封装的想法,对象的界面定义不太明确,系统可能更混乱.
另一种解决方案是在不同的访问修饰符下定义一对访问器:
class Pancake
attr_reader :has_sauce
private
attr_writer :has_sauce
public
def initialize(toppings)
sauces = [:maple, :butterscotch]
self.has_sauce = toppings.size != (toppings - sauces).size
end
end
Run Code Online (Sandbox Code Playgroud)
这完成了工作,但对于一个简单的存取器而言,这是一大块样板,而且非常坦率地说:ew.
那么有更好的,更Ruby的方式吗?
private 可以带一个符号arg,所以...
class Pancake
attr_accessor :has_sauce
private :has_sauce=
end
Run Code Online (Sandbox Code Playgroud)
或者
class Pancake
attr_reader :has_sauce
attr_writer :has_sauce; private :has_sauce=
end
Run Code Online (Sandbox Code Playgroud)
等等...
但是“原始”实例变量有什么问题呢?它们在您的实例内部;唯一可以按名称调用它们的代码是其中的代码,这些代码pancake.rb都是您的。事实上,他们以 开头@,我认为这让你说“blech”,是什么让他们成为私有的。如果您愿意,可以将其@视为速记private。
至于处理,我认为您的直觉很好:如果可以,请在构造函数中进行处理,或者如果必须,在自定义访问器中进行处理。
attr_reader 等等只是方法 - 没有理由你可以为自己的用途定义变种(我确实分享你的情绪)例如:
class << Object
def private_accessor(*names)
names.each do |name|
attr_accessor name
private "#{name}="
end
end
end
Run Code Online (Sandbox Code Playgroud)
然后private_accessor像你一样使用attr_accessor(我认为你需要一个比private_accessor更好的名字)
您可以输入attr_reader一个private范围,如下所示:
class School
def initialize(students)
@students = students
end
def size
students.size
end
private
attr_reader :students
end
School.new([1, 2, 3]).students
Run Code Online (Sandbox Code Playgroud)
这将按预期引发错误:
private method `students' called for #<School:0x00007fcc56932d60 @students=[1, 2, 3]> (NoMethodError)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4163 次 |
| 最近记录: |