作成するスクリプトがある程度大きくなると、 プログラムの各部分が相互に及ぼす悪影響をうまく排除する必要が出てくる。 このためには、プログラムの働きを大きなかたまりに分解し、 それぞれの独立性を高めた設計とする。これをプログラムのモジュール 化という。
ある種類のモノを考える。それに備わる性質を変数として、
動きや働きかけなどをメソッドとしてひとつの仲間にまとめ上げたものを
クラスという。クラス定義には class
を使う。
class SomeClass 〜〜定義本体〜〜 end
クラス名は大文字で始める。クラス定義にはメソッド定義, 定数定義,呼出し制限,またはさらに別のクラス定義を書ける。
定義したクラスの実体にあたるものをインスタンスという。 これまでよく用いた以下のような文はインスタンスの生成を意味する。
score = Array.new
この例は,様々な性質やメソッドを持つよう設計されたArrayクラスの,
実働的役割を担うモノ,つまりインスタンスを1つ作り,
それを score
変数に代入している。
配列(Arrayクラス)をずっと単純化して, 「日曜から土曜までの予定」7つの文字列しか保持できないクラス, Weekを定義してみる。クラス名は大文字で始める。
#!/usr/bin/env ruby # coding: euc-jp class Week def initialize(owner = "名なしの権兵衛") @week = Hash.new @days = %w(sun mon tue wed thu fri sat) setowner(owner) for day in @days @week[day] = "" end end def canonicalize_day(day) day[0,3].downcase end def set(day, plan) d = canonicalize_day(day) if @week.has_key?(d) then @week[d] = plan else STDERR.puts "#{day} という曜日はないのさ" nil end end def get(day) d = canonicalize_day(day) if @week.has_key?(d) then @week[d] else nil end end def getowner() @name end def setowner(name) @name = name end def display() printf("------ %sさんの予定 ------\n", @name) for d in @days do printf("%3s\t%s\n", d.capitalize, get(d)) end end end taro = Week.new("太郎") hana = Week.new("花子") taro.set("Thursday", "焼き肉") taro.setowner("TALOW!") hana.set("Thursday", "花見") taro.display hana.display
@
で始まる変数はインスタンス変数
といい,1つのインスタンスの内部に閉じ込められ,そのインスタンス
からしかアクセスできない変数である。
Rubyでは変数(ローカル変数)をメソッド間で共有することができない。 トップレベルで定義した変数も、メソッド内からは参照できない。
def foo() p x end x = 5 foo()
としても foo
メソッド内ではトップレベルの変数
x
にはアクセスできない。グローバル変数にすれば、
メソッド内からもアクセスできるようになるが、グローバル変数の使用は
プログラムの保守性、独立性、見通しのよさを著しく下げるため、
一定規模以上のプログラムでは通常用いない。複数のメソッド間で
値を共有する場合、通常は引数を用いる。値の永続性と適用範囲が
大きくなるものを作成する場合は、メソッド群をクラス化し
インスタンス変数を適切に利用する。
インスタンスが生成されるときに必ず呼ばれるメソッドを
コンストラクタ という。Rubyではコンストラクタを
initialize
という名前のメソッドが担う。new
されるタイミングで自動的に呼ばれるので,ここにインスタンス変数の定義
など,初期化に必要なコードを入れる。
インスタンスを作る必要のないもの,すなわち同じ種類の仕事をする
メソッドのみをグルーピングする目的のために module
が
利用できる。module
は class
文と同じ
形式で定義する。
#!/usr/bin/env ruby # coding: euc-jp module Menseki def sankaku(tei, tak) tei.to_f * tak / 2 end def daikei(jotei, katei, tak) (jotei+katei)*tak/2.0 end module_function :sankaku, :daikei end if $0 == __FILE__ p Menseki.sankaku(3,4) p Menseki.daikei(3,4) end
モジュール関数として外部から利用できるメソッド名を
module_function
で指定する。