2012-04-02 49 views
1

您是否应始终在ruby中创建附件(用于阅读和/或书写)?如果你有一个不想在外面重用的类,我不能直接使用实例变量吗?在ruby中直接使用实例变量是不是很糟糕?

我碰到的一个问题是,在测试中将@instance_vars残缺掉是有问题的。

+2

你可能会觉得这很有趣:http://talklikeaduck.denhaven2.com/2008/02/15/best-practice-patterns-accessors-and-encapsulation – 2012-04-02 22:10:14

+0

你能举一个你说什么的例子吗? – 2012-04-02 23:17:54

回答

3

当涉及到测试时,实例变量并不重要。您应该测试您的方法,以验证它们是否会产生正确的结果。

当您为属性定义读取器方法时,会将该属性公开给世界。如果属性的值来自实例变量,数据库,文件,运行时计算或任何其他内容,则无关紧要。人们可以调用该方法来获取价值。

同样,当你为一个属性定义一个编写器方法时,你让每个人都知道他们可以设置它,如果他们需要的话。价值在哪里并不重要。

只有你的方法定义你的公共API。其他一切都是实现细节。

在您的类定义,肯定是直接访问实例变量没有坏处:

@variable = :value 

没有理由调用方法,如果简单的分配是你所需要的。当然,有时你需要更复杂的功能。延迟初始化的,例如:

def variable 
    @variable ||= :value 
end 

# ... 

variable.to_s 

如果你的方法是仅供内部使用,你不应该将它包括在公共的API中。将其标记为私有:

private :variable 

说实话,虽然没有什么东西真的被锁在Ruby中。即使没有setter方法,人们可以方便地与你的对象篡改,如果他们真的想:

class << (object = Object.new) 
    private 
    def variable; @variable end 
end 

object.variable 
# NoMethodError: private method `variable' called 

# send bypasses access control 
object.send :variable 
# => :value 

object.instance_variables 
# => [:@variable] 
object.instance_variable_get :@variable 
# => :value 

object.instance_variables.each do |variable| 
    object.instance_variable_set variable, nil 
end 
object.instance_variable_get :@variable 
# => nil 
+0

如果一个方法使用了一个实例变量,我需要能够在测试过程中将它存根:http://stackoverflow.com/questions/9971192/stub-an-instance-variable-using-mocha – m33lky 2012-04-02 21:38:07

+0

@ m33lky,你不' t存根变量,则存根方法。我不熟悉'mocha',但是这里是如何在'RSpec':'(obj = MyClass.new).stub(:method1).and_return:new_value'中完成的。之后,'obj.method1'将返回':new_value'。 – 2012-04-02 22:03:06

+0

对不起,这是一个不好的例子。我是单位测试方法本身。它有更多的逻辑,但它取决于一个实例变量。 – m33lky 2012-04-02 22:07:59

1

我认为accessor是更多的东西,可以帮助你有些时候,当你想在设置或执行任务获取/设置新值之前验证新变量。如果你确定你不需要它,我认为最好留在实例变量中。否则,您可以在开始时创建这些代码,以便在您有大量代码时您不必在稍后创建它们,并且可以节省大量时间。

1

实例变量是为了将有问题的实例的上下文中使用。如果您需要与其他对象或其他对象交换数据,则应根据需要使用attr_readerattr_accessor来暴露它们,前提是不要编写自己的方法来实现此目的。

访问器方法充当关守,并提供机会让您验证外部调用者不会弄乱您的内部状态。面向对象设计的一个原则是对象承担筛选输入的责任。如何处理错误的输入取决于您,无论是忽略它,抛出异常还是在其他事件中记录错误。

如果您没有处理错误的输入,并因此而崩溃,它最终会成为您的“错误”,您将位于堆栈跟踪的顶部。先前拒绝错误的值会在问题发生的时候显示出问题,而不是在执行的后面,当时您可能已经失去了分配的来源。

通常,您不希望人们访问您的数据,除非他们有充分的理由。直接访问和修改另一个对象的实例变量是不好的形式。

有些语言甚至使得几乎不可能直接改变对象的内部状态,但Ruby在这方面相当随意。尽管如此,仅仅因为可以做的事情并不意味着它应该。

当您定义访问器时,是否在该实例的实现中使用它们取决于您。有时直接访问它们会更方便,因此调用@var而不是self.var,但有些情况下使用访问器会提供实例变量不支持的其他功能。由于您拥有单一的控制点,因此它还可以让您的应用程序更轻松地重构。