11

次のようなクラス階層が与えられます。

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ですAか? つまり、クラスのインスタンスにmy_obj = A.new(param)なるか、チェックインされるの値に依存します。my_objBCparamA.initialize(param)

私のユースケースでは、使用するサブクラス (BまたはC) と親クラス ( A) が基本的に実際に使用されることはありません。Bかどうかを決定する論理をC共通の祖先に移すのは良い考えかもしれないと思いました。

これが不可能な場合 (またはスタイルが悪い場合)、チェックをどこに置き、paramどのクラスを初期化するかを決定する必要がありますか?

4

3 に答える 3

12

ここで基本的なオブジェクト指向の原則を破っています。クラスはサブクラスについて何も知らないはずです。もちろん、原則を破る必要がある場合もありますが、ここで破る明確な理由はありません。

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

于 2012-06-17T23:36:46.583 に答える
4

問題は、の戻り値initializeが無視されることです。を呼び出すと次のようになりますA.new

  • new呼び出された特別なクラス メソッドを呼び出しallocateます -- これはクラスの空のインスタンスを返します
  • newinitialize次に、 によって返されたオブジェクトを呼び出し、オブジェクトallocateを返します。

やりたいことを行うには、オーバーライドして、やりたいことを実行させる必要があります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

ただし、他にも考慮すべきことがあります。ifAが実際に単独で使用されることがない場合は、何らかのファクトリ メソッドを使用するか、単純な if ステートメントを使用する必要があります。例えば:

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

デザインは、実際に何に使用するかによって異なります。たとえば、HTML など、何かの複数のバージョンを処理するために使用できるクラスがある場合、メイン クラスHTMLParserをオーバーライドnewして、そのサブクラスのいずれかを返すことができます: HTML1ParserHTML2ParserHTML3ParserHTML4Parser、およびHTML5Parser.

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

def self.new(args*)
  obj=allocate
  obj.send(:initialize, *args)
  obj
end
于 2012-06-17T19:34:44.440 に答える
0

self.instantiatenew をオーバーライドする代わりに、を呼び出すメソッドを作成できます.new

于 2020-06-26T20:43:27.683 に答える