2012-06-17 12 views
9

は、クラス階層を考える:Aを初期化するとき親クラスの初期化中にサブクラスの新しいインスタンスを返す方法次のように

class A 
    def initialize(param) 
    if param == 1 then 
     #initialize and return instance of B 
    else 
     #initialize and return instance of C 
    end 
    end 
end 

class B < A 
end 

class C < A 
end 

それは実際に初期化し、BまたはCのインスタンスを返すことが可能ですか?私。 my_obj = A.new(param)の場合paramの値に応じてBまたはCのインスタンスがmy_objになり、A.initialize(param)にチェックインされます。

私の使用状況では、使用するサブクラス(BまたはC)と親クラス(A)は基本的に実際には使用されません。 BまたはCのいずれかが共通の祖先になるかどうかを判断するロジックを変更することをお勧めします。

これができない場合(またはスタイルが悪い場合)、paramのチェックとどのクラスを初期化するのかを確認する必要がありますか?

+1

同様の質問が以前に回答されました。おそらくあなたが探しているのはファクトリメソッドです。 http://stackoverflow.com/questions/1515577/factory-methods-in-rubyを見てください。http://stackoverflow.com/a/1515580/1128705の回答があなたのニーズに合っていると思います。 –

答えて

8

あなたがここで基本的なオブジェクト指向の原則を破っている - のクラスは自分について何も知らないはずですサブクラス。もちろん、時には原則が破られるべきですが、ここでそれを行う理由はありません。

もっと良い解決策は、インスタンス化ロジックを別のクラスのファクトリメソッドに移すことです。ファクトリメソッドは、上記のAの初期化子と同じ引数をとり、適切なクラスのインスタンスを返します。

+0

大声で言ってくれてありがとう。 :)私は最終的に、別のモジュールに 'initiate_A'メソッドを書きました。これは決定を行い、新しいオブジェクトを返します。 –

+0

これは適切なケースが1つまたは2つあります。私が答えて言ったように、あなたがパーサクラスを持っていれば、それは例えば言語の異なるバージョンを扱わなければならないでしょうか?適切なバージョンのデータに適切なサブクラスのインスタンスを返すコンストラクタを使用できます。 HTML5は良い継承関係ではありません。私は何か分かりません。 – Linuxios

+0

私たちはお互いに同意しています - この原則は、正当な理由があるときに壊れる可能性があります。あなたの例が気に入っていないかどうかわかりませんが、抽象工場の場合のように聞こえます。 – ComDubh

3

事実は、戻り値initializeは無視されます。これは

  • newが、その後allocateによって返されたオブジェクトのinitialize呼び出すクラスの空のインスタンスを返し、オブジェクトを返します -

    • newallocateと呼ばれる特殊なクラスメソッドを呼び出します。ここでは、A.newが呼ぶときに何が起こるかです

    あなたがやりたいために、あなたはnewをオーバーライドして、それはあなたがやりたいようにする必要があり:

    class A 
        def self.new(args*) 
        if(args[0]==1) 
         B.new(*args[1..-1]) 
        else 
         C.new(*args[1..-1]) 
        end 
        end 
    end 
    

    他にも何か考慮する必要があります。 Aが本当に単独で使用されることがない場合は、何らかのファクトリメソッドを使用するか、単純なif文を使用する必要があります。例:

    def B_or_C(param,args) 
        (param == 1 ? B : C).new(args) 
    end 
    

    デザインは実際に使用しているものによって異なります。たとえば、HTMLのように複数のバージョンを扱うために使用できるクラスがある場合、をオーバーライドし、そのサブクラスのいずれかを返すメインクラスHTMLParserを持つことができます:HTML1ParserHTML2ParserHTML3ParserHTML4ParserHTML5Parser

    注:無限ループを防ぐために、サブクラスでデフォルトにnewメソッドをオーバーライドする必要があります。

    def self.new(args*) 
        obj=allocate 
        obj.send(:initialize, *args) 
        obj 
    end 
    
  • +0

    お返事ありがとうございます。しかし、 'A'で' self.new'をオーバーライドして 'A.new(params)'を呼び出すと、エラーが出ます: 'SystemStackError:stack level too deep'。 BとCの "コンストラクタ"が何らかの形で "コンストラクタ"を呼んでいるので、A.newの中の 'B.new'(または' C.new')を無限ループにするのは、 'A'、すなわち' A.new'。 –

    +0

    遺産のため –

    +0

    @Torbjoern:編集を参照してください。 – Linuxios

    関連する問題