5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rubyでクラスの属性をうまく継承する

Posted at

Goal

  • 抽象クラスを定義して、クラスの属性とメソッドをサブクラスに継承させたい
  • サブクラスから抽象クラスの属性を上書きできるようにしたい
  • サブクラスでクラス属性を上書きしなかった場合、抽象クラスで定義された属性をデフォルトで使用したい
  • デザインパターン苦手科目ですが、(たぶん)テンプレートメソッドパターンと同じことができます

Code

class AbstractModel

  @primary_key  = nil
  @table_name   = 'abstract'
  @storage      = 'file'

  class << self
    attr_accessor :primary_key, :table_name, :storage

    def inherited(klass)
      klass.primary_key = @primary_key
      klass.table_name  = @table_name
      klass.storage     = @storage
    end
  end

  def print_primary_key
    p self.class.primary_key
  end

  def print_table_name
    p self.class.table_name
  end
end

class Person < AbstractModel
  @primary_key  = 'person_id'
  @table_name   = 'persons'

  def print_storage
    p self.class.storage
  end
end

class Sport < AbstractModel
  @primary_key  = 'sport_id'
  @table_name   = 'sports'

  def print_storage
    p self.class.storage
  end
end

##
## クラスメソッドからクラスの属性が取得できることを確認
##
p AbstractModel.primary_key
  # nil
p Person.primary_key
  # "person_id"
p Sport.primary_key
  # "sport_id"

abs     = AbstractModel.new
person  = Person.new
sport   = Sport.new

##
## 親クラスから継承されたインスタンスメソッドが使えること
## インスタンスメソッドからも自分のクラスの属性が取得できることを確認
##
abs.print_table_name
  # "abstract"
person.print_table_name
  # "persons"
sport.print_table_name
  # "sports"

##
## サブクラスで上書きしていない属性にアクセスすると親クラスの値がデフォルトになっていることを確認
##
person.print_storage
  # "file"
sport.print_storage
  # "file"

親クラス(AbstractModel)で定義されたクラスインスタンス変数はサブクラス(Person, Sport)に継承されないが、クラスメソッドは継承される.
これはつまり、クラスインスタンス変数に対してattr_accessorを指定してやるとクラスインスタンス変数への入出力がメソッド化されるため、サブクラスに受け継ぐことができる(Person, Sportに対してprimary_key、primary_key=などのメソッドがよべる)ようになる.
けれども、これらの継承されたクラスメソッドが読み書きするのはサブクラス(Person, Sport)のクラスインスタンス変数なので、親クラス(AbstractModel)の属性をデフォルトとして使いたいならばinheritedを使うなどしてサブクラスのクラスインスタンス変数にコピーする必要がある.

また、インスタンスメソッドからクラスインスタンス変数を使うときには、メソッドのレシーバのクラスインスタンス変数に確実にアクセスできるようself.classをつけてよびだす.

もっとスマートな方法あれば教えて下さい.

References

以下の記事参考にさせていただきました.
http://qiita.com/a-suenami/items/bca7deefbe4ce9db103f

Environment

% uname -a
Linux *** 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

% ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]

% cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m
5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?