5.モジュール
1.モジュール
モジュールは、基本的にはクラスと同じものです。
クラスは、このモジュールを継承しています。
モジュールの用途は、主に名前空間とミックスインとしての利用です。
クラスを使用しても同じことが多いですが、
基本的にインスタンスの作成を目的としないものにはモジュールを使用します。
クラスは、このモジュールを継承しています。
モジュールの用途は、主に名前空間とミックスインとしての利用です。
クラスを使用しても同じことが多いですが、
基本的にインスタンスの作成を目的としないものにはモジュールを使用します。
2.クラスとの違い
- 1.インスタンス生成の可否
-
モジュールはインスタンスを作成することができません。
module Mod end Mod.new # => ERROR
- 2.継承の可否
-
モジュールは、サブクラスを持つことができません。
module SuperMod end module Mod < SuperMod # => ERROR end
ただし、ミックスインで同等のことが可能です。
module SuperMod end module Mod include SuperMod end
- 3.Mix-in の可否
-
モジュールは、ミックスインすることができますが、クラスはできません。
module Mod end class Hoge include Mod end include Hoge # => ERROR
- 4.メソッドの有無
-
Class は、Module を継承しているため Module のメソッドをすべて使用できますが、例外もあります。
Module#module_function、Module#extend_object、Module#append_features
これら、3つのメソッドはクラスで使用することができません。
3.名前空間
名前空間は、名前の衝突を防ぐための手段です。
関連する定数やクラスやモジュールをグループにまとめます。
同名のものがあっても望んだオブジェクトを参照できます。
通常は、グローバル空間への定義は避けるので、クラスや定数はモジュールに内包します。
関連する定数やクラスやモジュールをグループにまとめます。
同名のものがあっても望んだオブジェクトを参照できます。
通常は、グローバル空間への定義は避けるので、クラスや定数はモジュールに内包します。
CONST = 0 module ABC CONST = 123 module DEF CONST = 456 end end p CONST, ABC::CONST, ABC::DEF::CONST include ABC p CONST, ABC::CONST, DEF::CONST
4.モジュール関数
モジュール関数は、オブジェクト指向プログラミングが不要なときに使用します。
module_function メソッドを使用すると、以降のメソッドをモジュール関数として定義します。
モジュール関数は、プライベートメソッドとクラスメソッドの2つの同じメソッドが定義されたものです。
例えば、RGSS 組み込み関数の load_data と save_data のようなものをモジュール関数として定義します。
また、関連するメソッドをまとめることができるため、管理も楽になります。
module_function メソッドを使用すると、以降のメソッドをモジュール関数として定義します。
モジュール関数は、プライベートメソッドとクラスメソッドの2つの同じメソッドが定義されたものです。
例えば、RGSS 組み込み関数の load_data と save_data のようなものをモジュール関数として定義します。
# 実装は省略
module RVData
DIR_DATA = "Data"
F_ACTOR = "#{DIR_DATA}/Actors.rvdata"
module_function
def load(filename)
end
def save(obj, filename)
end
end
$data_actors = RVData.load(RVData::F_ACTOR)
include RVData
save($data_actors, F_ACTOR)
こうすることで、冗長な名前を付けずに名前のバッティングを防ぐことができます。また、関連するメソッドをまとめることができるため、管理も楽になります。
5.ミックスイン
クラスには、継承という機能があり同じような機能を持つクラスを別々に作る必要はありません。
しかし、同じような機能でも、まったく別の目的のクラスであれば、継承での共有化は適切ではありません。
このような場合に、モジュールを使用すると、継承階層から独立した実装を共有することができます。
ミックスインには、クラスオブジェクトに行うincludeと特定のオブジェクトへ行うextendがあります。
複数のモジュールをインクルードした場合は、インクルード順に新しいものが上位となります。
include と extend の引数は、複数指定することができます。
モジュールをミックスインすると、そのクラスの継承階層にモジュールを割り込ませることができます。
クラスがモジュールを継承した形になりまので、super を使用するとモジュールのメソッドが呼ばれます。
また、モジュールと is_a の関係が作られます。
しかし、同じような機能でも、まったく別の目的のクラスであれば、継承での共有化は適切ではありません。
このような場合に、モジュールを使用すると、継承階層から独立した実装を共有することができます。
ミックスインには、クラスオブジェクトに行うincludeと特定のオブジェクトへ行うextendがあります。
module Mod end class Hoge # モジュールのメソッドを追加 include Mod # モジュールのインスタンスメソッドをクラスメソッドとして追加 extend Mod def initialize # include と同じ意味 self.extend(Mod) end end # 特異メソッドとして追加 Hoge.new.extend(Mod)クラスは、単一継承のみをサポートしていますが、このミックスインを使うと多重継承を行うことができます。
複数のモジュールをインクルードした場合は、インクルード順に新しいものが上位となります。
include と extend の引数は、複数指定することができます。
モジュールをミックスインすると、そのクラスの継承階層にモジュールを割り込ませることができます。
クラスがモジュールを継承した形になりまので、super を使用するとモジュールのメソッドが呼ばれます。
また、モジュールと is_a の関係が作られます。
module M def a; "M"; end def b; "M"; end def c; "M"; end end class A def a; "A"; end def c; "A"; end end class B < A include M def b; "B"; end def c; super; end end p B.ancestors # => [B, M, A, Object, Kernel] a = B.new p a.a, a.b, a.c # => "M", "B", "M" p a.is_a?(M) # => true
6.今回のポイント
・ インスタンスの作成が不要なクラスはモジュールで実装する
・ 関連のないクラスで機能を共有するためにモジュールを使用する
・ グローバル空間での定数やメソッドの定義は避ける
・ 関連のないクラスで機能を共有するためにモジュールを使用する
・ グローバル空間での定数やメソッドの定義は避ける