クラスとモジュール

作成するスクリプトがある程度大きくなると、 プログラムの各部分が相互に及ぼす悪影響をうまく排除する必要が出てくる。 このためには、プログラムの働きを大きなかたまりに分解し、 それぞれの独立性を高めた設計とする。これをプログラムのモジュール 化という。

クラス

ある種類のモノを考える。それに備わる性質を変数として、 動きや働きかけなどをメソッドとしてひとつの仲間にまとめ上げたものを クラスという。クラス定義には class を使う。

class SomeClass
  〜〜定義本体〜〜
end

クラス名は大文字で始める。クラス定義にはメソッド定義, 定数定義,呼出し制限,またはさらに別のクラス定義を書ける。

インスタンスの生成

定義したクラスの実体にあたるものをインスタンスという。 これまでよく用いた以下のような文はインスタンスの生成を意味する。

score = Array.new

この例は,様々な性質やメソッドを持つよう設計されたArrayクラスの, 実働的役割を担うモノ,つまりインスタンスを1つ作り, それを score 変数に代入している。

簡単なクラスの例

配列(Arrayクラス)をずっと単純化して, 「日曜から土曜までの予定」7つの文字列しか保持できないクラス, Weekを定義してみる。クラス名は大文字で始める。

week.rb

#!/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 が 利用できる。moduleclass 文と同じ 形式で定義する。

menseki.rb

#!/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 で指定する。


目次