2012-04-02 9 views
1

あなたはいつもルビーで(読み書きのための)アクセスを作成する必要がありますか?外部で再利用することを目的としたクラスがない場合は、インスタンス変数を直接使用することはできませんか?ルビーでインスタンス変数を直接使用するのは悪いフォームですか?

私が遭遇した問題の1つは、テストで@instance_varsをスタブアウトすることは問題があるということです。

+2

これは興味深いかもしれません:http://talklikeaduck.denhaven2.com/2008/02/15/best-practice-patterns-accessors-and-encapsulation –

+0

あなたが話していることの例を挙げることができますか? –

答えて

3

インスタンス変数はテスト時には関係ありません。正しい結果が得られることを確認するには、の方法をテストする必要があります。

属性の読み取りメソッドを定義すると、その属性がワールドに公開されます。属性の値がインスタンス変数、データベース、ファイル、実行時の計算などから得られるかどうかは関係ありません。人々は値を得るためにメソッドを呼び出すことができます。

同様に、属性のライターメソッドを定義すると、必要に応じて、設定できることを皆に知らせることになります。値がどこに行くかは関係ありません。

あなたのメソッドだけがパブリックAPIを定義します。それ以外は実装の詳細です。

@variable = :value 

、単純な割り当てが必要なのであればメソッドを呼び出すする理由はありません:あなたのクラス定義内

は、確かに直接インスタンス変数にアクセスしても害はありません。もちろん、より洗練された機能が必要な場合もあります。レイジー初期設定。例:

def variable 
    @variable ||= :value 
end 

# ... 

variable.to_s 

あなたのメソッドが内部使用のみの場合は、公開APIに含めないでください。非公開としてください:

private :variable 

本当にRubyには何もロックされていません。

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

+0

@ m33lky、変数をスタブし、メソッドをスタブします。私は 'mocha'に慣れていませんが、' RSpec'で 'obj = MyClass.new).stub(:method1).and_return:new_value'でどのように行われるのです。その後、 'obj.method1'は':new_value'を返します。 –

+0

申し訳ありませんが、悪い例でした。私はメソッド自体をテストしています。より多くのロジックがありますが、インスタンス変数に依存します。 – m33lky

1

私は、新しい値の取得/設定時にタスクを設定または実行する前に、新しい変数を検証するときに、いつか助けてくれるアクセサがあると思います。もしあなたがそれを必要としないと確信しているなら、私はそれがインスタンス変数と一緒にいる方が良いと思います。それ以外の場合は、最初にすでに作成したものを作成することができます。そのため、後で大量のコードを作成する必要がなく、時間を大幅に節約できます。

1

インスタンス変数は、問題のインスタンスのコンテキスト内で使用されることを意図されています。でも、setterメソッドなしで、人々が簡単に、彼らが本当にしたい場合は、あなたのオブジェクトを改ざんすることができます。他のオブジェクトや他のインスタンスとデータを交換する必要がある場合は、それを容易にする独自のメソッドを記述していない場合は、必要に応じてattr_readerまたはattr_accessorで公開する必要があります。

アクセサーメソッドはゲートキーパーとして機能し、外部呼び出し元が内部状態を混乱させないことを検証する機会を提供します。オブジェクト指向設計の1つの原則は、オブジェクトが入力をスクリーニングする責任を負うということです。悪い入力をどう扱うかは、それを無視したり、例外をスローしたり、他のものの間でエラーを記録したりするあなた次第です。

不良入力を処理せずに後でクラッシュすると、「フォルト」になり、スタックトレースの一番上に表示されます。不正な値を以前に拒否した場合は、問題が発生したときに正確に表示されますが、その割り当てがどこから来たのかを忘れてしまったときには実行されません。

一般的に、理由がない限り、人々はあなたのデータにアクセスしたくありません。別のオブジェクトのインスタンス変数に直接アクセスして変更するのは悪いフォームです。

言語の中には、オブジェクトの内部状態を直接変更することがほとんど不可能になるものもありますが、Rubyはこの点でかなりカジュアルです。それでも、何かできることがそれを意味するわけではありません。

アクセサーを定義するときは、そのインスタンスの実装内でアクセサーを使用するかどうかはあなた次第です。場合によってはself.varの代わりに@varを呼び出して直接アクセスするほうが便利な場合もありますが、アクセサーを使用するとインスタンス変数にはない追加機能が提供されることがあります。単一のコントロールポイントがあるため、後でアプリケーションのリファクタリングを簡単にすることもできます。

関連する問題