Rubyのオブジェクト指向において、クラスの継承は「is-a」(〜である)関係を表現するのに適しています。しかし、「has-a」(〜を持つ)や「can-do」(〜ができる)といった**振る舞い(ビヘイビア)**を複数の異なるクラス間で共有したい場合があります。
他の言語では「インターフェース」や「トレイト」で解決するこの問題を、Rubyはモジュール (Module) と ミックスイン (Mix-in) という強力な仕組みで解決します。
module キーワードで定義されるモジュールには、大きく分けて2つの主要な役割があります。
include することで、インスタンスメソッドとして機能を追加します。これはRubyの「多重継承」の代替手段です。プログラムが大規模になると、異なる目的で同じ名前のクラス(例: Database::User と WebApp::User)を使いたくなることがあります。モジュールは、これらを区別するための「仕切り」として機能します。
名前空間内の要素には、:: (スコープ解決演算子) を使ってアクセスします。
ruby module_example.rbモジュールの最も強力な機能がミックスインです。これにより、クラスは継承ツリーとは無関係に、モジュールの振る舞い(インスタンスメソッド)を取り込むことができます。
include を使うと、モジュールはクラスの継承チェーン(祖先チェーン)に挿入されます。具体的には、include したクラスのスーパークラスの「直前」に挿入されます。
ruby mix_in_example.rbDuck と Airplane は全く異なるクラス(Bird のサブクラスと、Object のサブクラス)ですが、Flyable モジュールを include することで fly メソッドを共有できています。
include と extend は、モジュールのメソッドをどこに追加するかが異なります。
include: モジュールのメソッドを、クラスのインスタンスメソッドとして追加します。extend: モジュールのメソッドを、クラスのクラスメソッド(特異メソッド)として追加します。ruby extend_example.rbRubyのアクセスコントロールは、他の言語と少し異なる振る舞い、特に private の動作に特徴があります。
public (デフォルト)
object.)を省略しても、明示しても構いません。private
self. を付けずに、クラス内部(またはサブクラス)からのみ呼び出せます。protected
private と似ていますが、同じクラス(またはサブクラス)の他のインスタンスをレシーバとして呼び出すことができます。ruby access_control_demo.rbこの例では、transfer (public) が内部で withdraw (private) を呼び出し、引数で受け取った other_wallet の deposit (protected) を呼び出しています。deposit は protected なので、other_wallet. というレシーバを明示しても Wallet クラス内からは呼び出せます。
module キーワードで定義され、名前空間とミックスインの2つの役割を持ちます。
:: を使って定数やクラスをグループ化し、名前の衝突を防ぎます。include することでモジュールのメソッドをインスタンスメソッドとしてクラスに追加できます。これは多重継承の代わりとなる強力な機能です。extend は、モジュールのメソッドをクラスメソッドとして追加します。public, private, protected でメソッドの可視性を制御します。private は「レシーバを指定して呼び出せない」というユニークな制約を持ちます。Enumerable モジュール(第6章で少し触れました)のように、include したクラスに便利な機能を追加するモジュールを作成します。
Counter というモジュールを定義してください。Counter モジュールは count_items(item_to_find) というメソッドを持つものとします。include したクラスが items という名前の配列(Array)を返すインスタンスメソッドを持っていることを前提とします。count_items は、その items 配列内に item_to_find がいくつ含まれているかを返します。ShoppingCart クラスと WordList クラスを作成し、両方で items メソッドを実装し、Counter モジュールを include して count_items が動作することを確認してください。ruby practice8_1.rbprotected のユースケースを理解するための問題です。
Score クラスを作成します。initialize で @value (得点)をインスタンス変数として保持します。higher_than?(other_score) という public なインスタンスメソッドを定義してください。これは、other_score (Score の別のインスタンス)より自分の @value が高ければ true を返します。higher_than? メソッドの実装のために、value という protected メソッドを作成し、@value を返すようにしてください。higher_than? の内部では、self.value > other_score.value のように protected メソッドを呼び出してください。Score インスタンスを作成し、higher_than? が正しく動作することを確認してください。また、protected メソッドである value をインスタンスの外部から直接呼び出そうとするとエラーになることも示してください。ruby practice8_2.rb