Rubyのオブジェクト指向プログラミングでクラスとメソッドの基本を学ぶ
オープニングクラスとモンキーパッチ
Rubyでは、クラスで定義されたメソッドとそれ以外の文に違いはなく、すべて一行ずつ実行されます。次のような例です。
class Example
def method_1
puts "method 1"
end
end
class Example
def method_2
puts "method 2"
end
end
この例では、Exampleというクラスが最初に定義されたときにはまだ存在しないので、Rubyはこのクラスの定義を始め、後で定義されたときに、Rubyはクラスがすでに存在することを知り、新しいクラスを定義する代わりにそのクラスを返します。
このため、Rubyには、たとえ標準クラスライブラリのクラスであっても、すでに存在するクラスを開いて、その内容を動的に変更する機能が備わっている。たとえば、SDK の String クラスに、String から句読点や特殊文字を取り除くメソッドを追加できます: to_alphanumeric
class String
def to_alphanumeric
gsub /[^\w\s]/, ''
end
end
"H&&^^^ello".to_alphanumeric #==>Hello
そして、すべてのStringオブジェクトは、一般にオープンクラスと呼ばれる手法で、「英数字に変換」する機能を持つ。
なぜなら、多くの開発者がクラスを拡張しており、複数の拡張メソッドが同じ名前である場合、後のメソッドが前のメソッドを常に上書きしてしまうため、システム全体がクラッシュしてしまうからです。パッチ)。したがって、オープンクラスのテクニックを使用する際には注意が必要です。
インスタンス変数
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.method」で呼び出すことはできないので、「Classに "method "というメソッドがある」とは言えず、「Classに "method "というインスタンスメソッドがある」とは、そのクラスのインスタンスオブジェクトを作って、そのインスタンスオブジェクトを通してメソッドを呼び出さなければならない、ということです。
クラスメソッドを定義したい場合は、メソッドを定義する際に以下のようにクラス名を前置する必要があります。
class Person
def Person.name
@name = "xianlinbox"
end
end
クラス自体もオブジェクトである
Rubyでは、クラスはそれ自体がオブジェクトであり、オブジェクトに関するすべてのルールがクラスに適用されます。
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を継承しています。
クラスはモジュールを継承し、インスタンスを生成するためのnew()とallocate()メソッドが追加されたものです。
メソッドの発見と実行
オブジェクトがメソッドを実行しようとするとき、まずメソッドを探す必要があります。Rubyコンパイラがメソッドを探す方法は、まず自分のクラスを探し、それがなければ、そのクラスの祖先の連鎖を上がっていきます。
String.ancestors # => [String, Comparable, Object, Kernel, BasicObject]
あるクラスがモジュールを含むとき、コンパイラはそのモジュールをそのクラスに最も近い祖先の鎖に置きます。String クラスは Comparable モジュールを含み、Kernal は Object クラスに含まれます。
そのメソッドが実行されるときには受け手が必要であり、メソッドは受け手のオブジェクト(selfオブジェクトと呼ばれる)の中で実行される。一般に、selfオブジェクトは最後にメソッドを受け取ったオブジェクトが想定され、クラスやモジュールの定義では(あらゆるメソッド定義の外側でも)selfオブジェクトが想定される。
メソッドの動的起動
通常、メソッドは「オブジェクト名」で呼び出されます。Rubyにはクールな機能があって、呼び出したいメソッドの名前を引数としてsend()メソッドに渡せるので、コードを実行する最後の瞬間まで、どのメソッドを呼び出すか決めることができます。このテクニックは、例えば、プロジェクト内にプロファイルオブジェクトがあり、そのプロファイルに従って初期化され、使用中にユーザーによって異なる値が設定される可能性がある場合に非常に有効である。通常は、プロパティのキー値がどのプロパティに対応するかを判断し、次のコードで対応するセット・メソッドを呼び出します。
config.name = v if isNameProperty?(k)
config.password = v if isPasswordProperty?(k)
config.port = v if isPortProperty?(k)
...
こんな兄弟みたいなコード群を見ていると、去勢したい衝動に駆られる。ダイナミックコールメソッドを使えば、以下のようにコードを簡略化することができる。
{{コード
得られた各キーの値によると、対応するプロパティのセットメソッドを呼び出すと、コードがはるかに新鮮な、後で設定オブジェクトを展開すると、ロードメソッドを変更する必要はありません。
動的に定義されたメソッド
Ruby では、メソッドを動的に呼び出すだけでなく、Module#define_method() メソッドを用いてメソッドを動的に定義することも可能です。例を示します。
load_config('config.properties').each do |k, v|
config.send("#{k}=", v)
end
この黒魔術を使えば、後で、複数の似たようなメソッドの違う部分をパラメータとして取り出し、1つのメソッド定義で全てを処理することができるようになります。
method_missing()メソッド
Rubyは動的言語であり、コンパイラはメソッド呼び出しの挙動を検出しないので、存在しないメソッドを呼び出すことができます。実行時に、対応するメソッドが見つからない呼び出しはすべて method_missing() メソッドを呼び出します。このメソッドは Kernal モジュールで定義されているので、すべてのオブジェクトはこのメソッドを継承しています。カーナルのmethod_missing()メソッドはNoMethodError例外を投げますが、これはコンパイラが行うことです。
しかし、このメソッドをオーバーライドすることで、面白いことができるようになります。例えば、Structを作成して、新しいプロパティが欲しいときに、値を代入するだけで、魔法のように生成されるとします。
class MyClass
define_method :doubleString do |args|
args * 2
end
end
t = MyClass.new
puts t.doubleString("he") # => hehe
このように、呼び出す側から見れば通常のメソッドと変わらないが、実際に受け取る側には対応するメソッドがないものを、Rubyの用語ではゴーストメソッドと呼んでいます。メソッドをカスタマイズするだけでなく、別のオブジェクトのメソッドに転送することもできますし、もちろん、転送の前後に独自のロジックをいくつかラップすることもできます。
ゴーストメソッドを処理するために method_missing を使用した後は、存在しないメソッドの呼び出しはすべてここに来ることになり、直感的でないエラーメッセージが出ることがあります (NoSuchMethod のようなヒントは表示されません)。したがって method_missing スキームを使う場合は、必ずその使用を制限して、親クラスの method_missing を呼び、もしそれがこの範囲に属していなければどんなエラーが表示されるか、報告されるか、というようにする必要があります。
予約済みメソッドを持つホワイトボードクラス
すべてのクラスには、親クラスから継承されたメソッドがたくさんあります。ダイナミックプロキシ技術を使う場合、ゴーストメソッドと本物のメソッド(想定外の継承メソッド)が衝突すると、後者が勝ってしまい、システムエラーになる。したがって、ダイナミックプロクシ技術を使用する場合は、プロクシクラス内の継承されたメソッドをほとんど削除することで、名前の衝突を回避することができます。_method メソッド
RubyのObjectクラスには、内部で使用されるメソッドがいくつかあります。それらを再定義したり、削除したりすると、何らかの原因でRubyがハングアップすることがあり、それを防ぐために、Rubyのp
関連
-
Ruby変数の詳細分析
-
画像フィルターアルゴリズムコードのRuby実装
-
win10でvirtualbox+vagrantでrubyの開発マシン環境を構築する
-
MongoDBに接続するためのRuby on Railsフレームワークアプリケーション チュートリアル
-
Rubyのgemパッケージ管理およびgemソース構築のチュートリアル
-
Rubyプログラムにおける正規表現の基本的な使い方に関するチュートリアル
-
RubyのXMLデータパースライブラリ「Nokogiri」の高度な使い方
-
RubyがWeb画像クローリングを実装
-
Ruby on Railsにおける国際化の簡単な紹介
-
Ruby on Railsのルーティング設定に関するいくつかのアドバイス
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
redisクラスタ構築のチュートリアルと発生した問題
-
Ruby on Rails ラックミドルウェア基礎学習チュートリアル
-
RubyのMonkey Patchの開発例
-
MacとLinuxでのruby+rails環境の構築
-
Rubyのオブジェクト指向のアプローチによるプログラミング学習雑学
-
Rubyのgemパッケージマネージャの使い方とbundlerによる複数バージョンのgemの管理
-
Rubyのデザインパターン。アダプタパターン実践ガイド
-
デザインパターンのうち、ProxyパターンとDecorativeパターンを使ったRubyのコード例
-
Ruby on Railsのビューの書き方に関するいくつかのアドバイス
-
Rubyのモジュールに関する基礎知識