2

初期化パラメータに応じて具体的なインスタンスを作成する抽象クラスを作成したいと思います。例:

class SomethingGeneric
def self.new(type, arg)

    class_name = "#{type.capitalize}Something"

    if obj.const_defined?(class_name)
        a_class = obj.const_get(class_name)
    else
        raise ArgumentError, "Concrete something '#{type}' was not found"
    end

    obj = a_class.new(arg)

    return obj
end
end # class

次に、FooSomething < SomethingGeneric、BarSomething < SomethingGeneric などが必要です。それから私がするとき:

obj = SomethingGeneric.new("foo", arg)

FooSomething インスタンスを取得します。

ここでの問題は、「新しい」方法です。私はSomethingGeneric.newを定義しましたが、FooSomethingとBarSomethingはSomethingGenericのサブクラスであるため、ここでは間違った引数で呼び出される「新しい」メソッドを継承しています:

obj = a_class.new(arg)

解決策の 1 つは、ファクトリ メソッド「new」に別の名前を使用することです。ただし、利便性にこだわり、「new」という名前の抽象スーパークラス ファクトリ メソッドを維持したいと考えています。

この問題を解決する最もクリーンで正しい方法は何ですか?

4

2 に答える 2

3

新しいメソッドは 1 つのパラメーターを取る必要があります: *args

配列から最初の項目をタイプ var として取得し、その項目を配列から削除して、残りの引数を次の新しい呼び出しに渡すことができます。

Array#shift は、最初のアイテムを提供してから削除します。

class SomethingGeneric
  def self.new(*args)

    type = args.shift
    class_name = "#{type.capitalize}Something"

    if obj.const_defined?(class_name)
        a_class = obj.const_get(class_name)
    else
        raise ArgumentError, "Concrete something '#{type}' was not found"
    end

    obj = a_class.new(*args)

    return obj
  end
end # class
于 2010-10-27T13:45:11.253 に答える
0

本当の問題は、この動作が何のために必要かということです。ファクトリなどが標準であるJavaのような言語から来ているようです。使用する特定のメソッドにオブジェクトが応答することを確認するために、この動作が必要ですか? インターフェイスを使用するのはどうですか?

何かのようなもの:

class GenericThing
  def name # Interface method
     # Return a String of the name of the GenericThing.
  end
end

class GenericSomething
  def name
    # ...
   end
 end

 class Whatever
   def self.method_that_uses_the_generic_interface(generic)
     if generic.respond_to?(:name) # Check for interface compliance
       generic.name
     else
        raise "Generic must implement the name method."
     end
   end
 end

本当に Abstract クラスを使用したい場合は、次のようにすることができます。

class AbstractGeneric
  def name
    raise "You must override name in subclasses!"
  end

 class GenericThing < AbstractGeneric
   def name
     "GenericThing"
    end
 end

 class GenericSomething < AbstractGeneric
   # ...
 end

 class Whatever
   def self.method_that_uses_the_generic_interface(generic)
     if generic.kind_of? AbstractGeneric
       generic.name
       # Will raise if the interface method hasn't been overridden in subclass.
     else
       raise "Must be a instance of a subclass of AbstractGeneric!"
     end
   end
 end

この場合、動作は次のようになります。

generic_thing = GenericThing.new
Whatever.method_that_uses_the_generic_interface(generic_thing)
=> "GenericThing"

generic_something = GenericSomething.new
Whatever.method_that_uses_the_generic_interface(generic_something)
# Will raise "You must override name in subclass!"

object = Object.new
Whatever.method_that_uses_the_generic_interface(object)
# Will raise "Must be an instance of a subclass of AbstractGeneric!"
于 2010-10-28T14:12:09.080 に答える