2010-10-27 39 views
2

我想創建一個抽象類,它將根據初始化參數創建具體實例。例如:如何在Ruby中創建「類集羣」(具有具體子類實例的工廠類)?

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) 

其中一個解決方案是使用的別稱工廠方法'新'。不過,我想堅持使用方便,並保留名爲'new'的抽象超類工廠方法。

解決此問題的最簡潔的正確方法是什麼?

+0

爲什麼?天啊!爲什麼? – Ariejan 2010-10-27 13:41:59

+0

@Ariejan爲什麼不呢? – 2013-08-22 06:46:04

回答

3

你的新方法應採取一個PARAM:* ARGS

你要抓住的第一個項目出數組作爲類型變種,然後從數組中刪除該項目,因此您可以通過休息的參數下降到下一個新的呼叫。

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 
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 

如果你真的想用一個抽象類,你可以這樣做:

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!" 
相關問題