Rubyオブジェクトプログラミングにおけるクラスと方法の基礎学習

6349 ワード

クラスとサルのパッチを開くRubyでは、クラス定義の方法は他の文と何の違いもなく、1行1行実行されます.次の例を示します.

class Example 
 def method_1 
  puts "method 1" 
 end 
end 
class Example 
 def method_2 
  puts "method 2" 
 end 
end 


この例では、Class Exampleを最初に定義したときに、まだExampleというClassが存在しないため、Rubyはこのクラスの定義を開始し、後でこのクラスを定義すると、Rubyはそのクラスが存在していることを発見し、新しいクラスを定義するのではなく、このクラスを返します.
この特性のため、Rubyは既存のクラスを開き、標準クラスライブラリのクラスであっても例外ではなく、その内容を動的に変更する能力を持っています.たとえば、SDKのStringクラスにStringの句読点と特殊文字を除去する方法を追加できます:to_alphanumeric

class String 
 def to_alphanumeric 
  gsub /[^\w\s]/, '' 
 end 
end 
“H&&^^ello”.to_alphanumeric #==>Hello 


そして、すべてのStringオブジェクトが「to_alphanumeric」という能力を備えており、この技術は一般的にオープンクラス技術と略称される.
上記のオープンクラス技術は、特に大規模なシステムでオープンクラス技術を使用して標準クラスライブラリを拡張する場合、多くの開発者がクラスを拡張しているため、複数の拡張方法の名前が同じである場合、後に定義されたものは常に前を上書きし、システム全体のクラッシュを招く.業界では、このような無謀な修正クラスをサルパッチ(Monkey Patch)と略称している.そのため、オープンテクノロジーを使用する場合は、慎重にしなければなりません.
インスタンス変数Rubyでは、インスタンス変数はオブジェクトに格納されているが、そのオブジェクトのクラスには関係なく、オブジェクトのインスタンス変数に値を割り当てると、そのインスタンス変数が生成される.

class Person 
 def name 
  @name = "xianlinbox" 
 end 
end 
p = Person.new 
puts p.instance_variables   #==>nil 
p.name 
puts p.instance_variables   #==>@name 


メソッドはオブジェクトとして、インスタンス変数(属性とも呼ばれる)のほかに、メソッドが必要です.ただしRubyではメソッドの定義はオブジェクトではなくオブジェクト自身のクラスにあるため,「同じクラスを共有するオブジェクトも同じメソッドを共有しなければならない」ためである.ただし、Classにはメソッドを呼び出すことができないため、「Class.method」というメソッドがあるとは言えません.Classにはインスタンスメソッド「method」があります.これは、クラスのインスタンスオブジェクトを作成し、インスタンスオブジェクトを介してメソッドを呼び出す必要があることを意味します.
クラスメソッドを定義する場合は、メソッドを定義するときに、次のようにクラス名の接頭辞を付ける必要があります.

class Person 
 def Person.name 
  @name = "xianlinbox" 
 end 
end 


クラス自体もオブジェクトRubyでClass自体もオブジェクトであり、オブジェクトに関するすべてのルールがClassに適用される.

puts "hello".class          #=> String 
puts String.class           #=> Class 
puts Class.class           #=> Class 
puts Class.instance_methods(false)  #=> [:superclass,:allocate,:new] 
puts Class.instance_variables    #=> nil 


クラスの継承システム

puts String.superclass    #=> Object  
puts Class.superclass     #=> Module 
puts Module.superclass    #=> Object 
puts Object.superclass    #=> BasicObjec 
puts BasicObject.superclass  #=> nil 


BasicObjectは、継承システムのルートノードです.すべてのクラスはObjectから継承されます.ClassはModuleの継承を強化し、new()メソッドとallocate()メソッドを追加してインスタンスを作成します.
メソッドの検索とRuby内のオブジェクトの実行方法はクラスで定義されており、オブジェクトがメソッドを実行したい場合は、まずメソッドを見つける必要がありますが、Rubyコンパイラがメソッドを検索する方法は、最初のステップで自分のクラスで探し、なければ、そのクラスの祖先チェーン(ancestors)に沿ってずっと上を探します.

String.ancestors    # => [String, Comparable, Object, Kernel, BasicObject] 


なぜここにComparableとKernalが現れるのか、これはModuleのメカニズムで、クラスincludeのモジュールがある場合、コンパイルはこのモジュールをクラスに最も近い祖先チェーンに配置し、StringクラスincludeはComparableモジュールを配置し、KernalはObjectクラスincludeに配置されるからです.
メソッドの実行に受信者が必要になると、メソッドは受信者オブジェクトで実行され、その受信者はいわゆるselfオブジェクトである.一般的にselfオブジェクトは、クラスおよびモジュールの定義(および任意のメソッドの定義外)において、最後にメソッドを受信したオブジェクトによって担当され、selfオブジェクトはクラスまたはモジュールによって担当される.
動的呼び出しメソッドの通常のメソッドの呼び出し方式は「オブジェクト名.メソッド名」であり,Rubyにはsend()メソッドにより呼び出したいメソッド名をパラメータとすることで,コード実行時にどのメソッドを呼び出すかを最終時刻まで決定できるというクールな特性があり,この技術を動的配布(Dynamic Dispatch)と呼ぶ.このテクノロジーは、たとえば、プロジェクトにプロファイルオブジェクトがある場合、プロファイルに基づいて初期化され、使用中にユーザーによって異なる値が設定される場合があります.通常、属性のキー値がどの属性に対応するかを判断し、対応するsetメソッドを呼び出します.コードは次のとおりです.

config.name = v if isNameProperty?(k)  
config.password = v if isPasswordProperty?(k)  
config.port = v if isPortProperty?(k)  
...  


このような実の兄弟のようなコードの山を見ていると、思わず去勢する衝動に駆られた.動的呼び出しメソッドを使用すると、コードは以下のように簡略化されます.

load_config('config.properties').each do |k, v|  
config.send("#{k}=", v)  
end 

取得したキー値ごとに、対応するプロパティのsetメソッドを調整すると、コードがすっきりし、configオブジェクトを拡張してloadメソッドを変更する必要はありません.
動的定義メソッドは、動的呼び出しメソッドに加えて、Module#define_を使用することで動的定義メソッドをサポートします.method()メソッドは、メソッド名とメソッドボディとして機能するブロックを提供してメソッドを定義します.例:

class MyClass  
define_method :doubleString do |args|  
args * 2  
end  
end  
t = MyClass.new  
puts t.doubleString("he")  # => hehe 


この黒魔法があれば、その後、複数の似たような方法の異なる部分をパラメータとして抽出し、1つの方法で定義してすべての方法を解決することができます.
method_missing()メソッドRubyは動的言語であり、コンパイラはメソッド呼び出し時の動作を検出しないため、存在しないメソッドを呼び出すことができます.実行時に、対応するメソッドが見つからない呼び出しはmethod_を呼び出します.missing()メソッドは、Kernalモジュールに定義されているため、各オブジェクトがメソッドを継承します.kernalでmethod_missing()メソッドでは、NoMethodErrorの異常が投げ出されます.これがコンパイラの仕事です.
しかし、私たちはこの方法を繰り返して、それを面白くすることができます.たとえば、Structを作成すると、新しいプロパティがほしいときに値を付けるだけで不思議に生成されます.

class MyStruct  
def initialize  
@attributes = {}  
end  
 
def method_missing(name, *args)  
attribute = name.to_s  
if attribute =~ /=$/  
@attributes[attribute.chop] = args[0]  
else  
@attributes[attribute]  
end  
end  
end  
s = MyStruct.new  
s.weibo = "@xianlinbox"  
puts s.weibo       # => @xianlinbox 


このように,呼び出し者としては一般的な方法と変わらないが,実際の受信者には対応する方法がなく,Ruby用語で幽霊法(Ghost Method)と呼ぶ.幽霊メソッドについては、このメソッドをカスタマイズする以外に、このメソッドを別のオブジェクトに転送する方法もあります.もちろん、転送前後に独自の論理をパッケージすることができます.この処理技術は、ダイナミックエージェント(Dynamic Proxy)と呼ばれ、前述したダイナミック呼び出し異曲同工と呼ばれています.
method_を使用しましたmissingが幽霊メソッドを処理すると、メソッドが存在しない呼び出しがすべてここに来るため、誤った情報が直感的でない問題(NoSuchMethodのようなヒントが見えない)を引き起こす可能性があります.そのため、method_を使用しています.missingスキームの場合、必ずその使用範囲を限定し、親クラスのsuperを呼び出す.method_missingメソッドは、この範囲に属さないように、何が間違っているのか、それとも何が間違っているのかを報告します.
ホワイトボードクラスと保存方法各クラスには、動的エージェント技術を使用する場合、幽霊メソッドと実際のメソッド(予想外の継承メソッド)が名前に衝突した場合、後者が勝つため、システムエラーが発生します.したがって、動的エージェント技術を使用する場合、エージェントクラスのほとんどで継承されたメソッドを削除することができ、名前の競合を回避し、継承メソッドを削除したクラス、いわゆるホワイトボードクラス(Blank Slate)であり、クラスメソッドを削除する方法は2つあり、1つはModule#undef_を呼び出すことである.Methodメソッド、1つはModule#remove_を呼び出すメソッド.
RubyのObjectクラスでは、内部で使用する方法がいくつかありますが、それを再定義したり削除したりすると、Rubyがわけのわからないドロップになる可能性があります.これを防ぐために、Rubyはこれらのメソッド名の前に「」を使います.先頭に立って、これらの方法を保留方法と呼び、これらの方法を修正しようとすると、Rubyは警告します.