質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.91%

rubyにおけるポリモーフィズムでサブクラス名による条件分岐

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 2,647

score 1235

Rubyにおいてsuperクラスの関数をサブクラスで呼び出すとき,その関数を呼び出したクラス名によって場合分けしたいと考えています。

#a,bは同じBaseクラスを継承している

a = A.new
b = B.new 

array = [a,b]

for i in (0...array.length)
    array[i].method();
end


#以下のような動作がしたい

Class Base

   def Base << self

      def method()
        if (クラスAなら)
          p 'This class is A !'
        else
          p 'This class is not A !'
        end
      end

   end

end

以上のコードはどう書くのがいい書き方になるでしょうか。メソッドの引数にflagなどを代入するやり方はできれば避けたいtです。よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+2

Base#method 中で 条件分岐させるのは、好ましくないです。
なぜなら、将来, Base を継承した C というクラスを作ったときに、Base#method を変更することが必要になるからです。

次のようにすると、Base を継承した C、D, ... をつくった場合でも、Base#method の変更は不要になります。
foo.rb

class Base
  def methodX
    puts 'This class is Base !'
  end
  def methodY
    puts "***(Base) This class is #{self.class} !"
  end
end

class A < Base
  def methodX
    puts 'This class is A !'
  end
end

class B < Base
  def methodX
    puts 'This class is B !'
  end
end

[A.new, B.new, Base.new].each do |x|
  x.methodX
end
puts
[A.new, B.new, Base.new].each do |x|
  x.methodY
end


実行結果

$ ruby foo.rb
This class is A !
This class is B !
This class is Base !

***(Base) This class is A !
***(Base) This class is B !
***(Base) This class is Base !

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/05 02:37 編集

    ありがとうございます。ここまでともなると派生先のクラスにメソッド記述した方が解りやすいかもしれませんね。今回はダックタイピングというほどではなく共通処理の中でスーパークラスのインスタンス変数の一部だけに違う値を代入させるということをさせたかったので色々試しましたが,結局条件分岐でメソッドを作る方針にしました。サブクラスにsuper入れてやる方法でやってましたがcase分岐の方がコードが少なく1つのファイルに修正すべきコードがまとまるのでこちらを採用します。

    キャンセル

+1

こんな感じですかね。

class Base
    def method
        case self
        when A
            puts "This class is A!"
        when B
            puts "This class is B!"
        else
            puts "I don't know this class!"
        end
    end
end

class A < Base
end

class B < Base
end

a = A.new
b = B.new

array = [a,b]

array.each do |x|
    x.method
end

あるいは、a.is_a?(A) とか a.instance_of?(A) を使います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/04 13:45

    case文だとselfだけでも型判別してくれるんですね
    勉強になりました!

    キャンセル

+1

.class.name でクラス名を得ることができます。
次のコードを参照してください。
1.rb

def util_method(obj)
  class_name = obj.class.name
  p "This class is B #{class_name}!"
  class_name
end

class Base
  def method
    util_method(self)
  end
end

class A < Base
end
class B < Base
end

p [A.new, B.new, Base.new].map{ |x| x.method }
puts
p ['abc', [], 1.2, A.new].map{ |x| util_method(x) }


実行結果:

$ ruby 1.rb
"This class is B A!"
"This class is B B!"
"This class is B Base!"
["A", "B", "Base"]

"This class is B String!"
"This class is B Array!"
"This class is B Float!"
"This class is B A!"
["String", "Array", "Float", "A"]

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

0

self.kind_of?(A)
でクラスを判断できます。

#!/usr/bin/env ruby
# -*- encoding:utf-8 -*-
#

class Base
    def method()
        if self.kind_of?(A)
            p 'This class is A !'
        else
            p 'This class is not A !'
        end
    end
end

class A < Base
end

class B < Base
end

a = A.new
b = B.new 

array = [a,b]

for i in (0...array.length)
    array[i].method();
end

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/04 13:27 編集

    こんな簡単にできるんですね!
    ありがとうございます!

    キャンセル

  • 2016/03/04 13:33

    つかえます。サンプルも掲載しましたので、コピペで検証してみてください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る