2011-07-05 13 views
6

Temel XML'yi (bir OXM gibi) modelleyen bir dizi Ruby nesnesine sahibim. Maalesef, XML değiştiriliyor ve ilgili sürüm çarpıyor. Her iki sürümü de ele alabilmek için Ruby nesnelerini güncellemem gerekiyor. Yöntemlerimde bir ton if/else cümlesinden daha temiz bir şey isterim, çünkü bu muhtemelen tekrar meydana gelebilir. Bunu halletmek için deyimsel bir Ruby yolu var mı? BenBir Ruby Nesnesi Sürümünü Oluşturma

class XMLModel 
    class V1 
    # V1 specific implementation 
    end 

    class V2; 
    # V2 specific implementation 
    end 

    def initialize 
    # create a new V? and set up delegation to that specific version of the object 
    end 

    def from_xml(xml_string) 
    # use the XML string to determine correct version and return a 
    # specific version of the object 
    end 
end 

yukarıdaki yöntem hakkında güzel bir şey, her versiyon kodu içinde farklıdır ve bana eklemek için izin olmasıdır/damla yani sınıflar "sürüm" Çeşitli için proxy olarak baz sınıfını kullanmayı düşünüyorum geriye dönük uyumluluk testine sahip versiyonlar. Kötü olan şey, büyük olasılıkla kod çoğaltmasıyla sonuçlanacağım. Ayrıca, bu durumda, XMLModel.new yeni bir XMLModel döndürür, XMLModel.from_xml fabrika yöntemi yeni bir XMLModel::V1 döndürür.

Fikirler?

cevap

2

Neden XMLModel'den miras alınan alt sınıfı oluşturmayın, sonra sınıflar arasındaki karar kodun yalnızca bir noktasındadır.

class XMLModel_V1 < XMLModel 
    def from_xml(xml_string) 
     # do V1 specific things 
    end 
end 

class XMLModel_V2 < XMLModel 
    def from_xml(xml_string) 
     # do V2 specific things 
    end 
end 


# Sample code wich shows the usage of the classes 
if(V1Needed) 
    m = XMLModel_V1 
else 
    m = XMLModel_V2 
end 
+0

Eğer XMLModel başlatma (yani 'new') 'de' if' deyimi ... Ben ayrı fabrika intialization, yani 'XMLModel.create' kullanmadan görünüyor olamayacağını gizlemek Can. Kullanıcıların sürüm hakkında bilgi sahibi olmamasını ve nesneyi normal bir Ruby nesnesi olarak kullanabilmesini ve 'XMLModel.new' adını vermesini ve böylece modelin arkasındaki tüm uygulamayı gizlemesini istemiyorum. –

+0

'' new''i geçersiz kılabilirsiniz. Varsayılan yeni yöntem (sanırım) şöyle bir şeydir: 'def new (* args); obj = tahsis etmek; obj.initialize (* args); retrun obj; End one Tek liner için üzgünüm, yorumlar ve kodlar iyi karışmıyor. – Ian

+0

redefining daha fazla ayrıntı ile bir cevap ekledi :: yeni – Ian

3

Sizin için birkaç seçenek görüyorum.

üzerinde method_missing numaralı proxy yöntem çağrılarını kullanabilirsiniz.

class XMLModel 

    def load_xml(xml) 
    version = determine_version(xml) 
    case version 
    when :v1 
     @model = XMLModelV1.new 
    when :v2 
     @model = XMLModelV2.new 
    end 
    end 

    def method_missing(sym, *args, &block) 
    @model.send(sym, *args, &block) 
    end 

end 

Başka bir seçenek dinamik XMLModel örneğine belirli sürümden yöntemleri kopyalamak olacaktır. Ancak, tamamen gerekli olmadıkça bunu yapmaktan vazgeçerim.

Üçüncü seçenek, bu sürüme özgü yöntemlere sahip her sürüm için bir modül oluşturmaktır. Daha sonra, bir proxy nesnesine sahip olmak yerine, sadece belirli bir sürüm için modülü dahil edersiniz.

module XMLModelV1 
    #methods specific to v1 
end 

module XMLModelV2 
    #methods specific to v2 
end 

class XMLModel 
    #methods common to both versions 

    def initialize(version) 
    load_module(version) 
    end 

    def load_xml(xml) 
    load_module(determine_version(xml)) 
    end 

private 

    def load_module(version) 
    case version 
    when :v1 
     include XMLMOdelV1 
    when :v2 
     include XMLModelV2 
    end 
    end 
end 
+0

XML yüklenirken çalışır, ancak XML oluşturmaya çalışırken işe yaramaz. Bunun için de ('' '' '' '' '' '' '' '' '' '' '' n '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' –

+0

'to_xml' yöntemi, belirli sürüm sınıflarından birinin parçası olmaz mıydı? – Jeremy

+0

Evet, to_xml her sürüm sınıfının bir parçası olacaktır, ancak kullanıcı bir XML belgesini sıfırdan oluşturmak istiyorsa, yeni bir (boş) nesne alması gerekir; Rails ActiveRecord gibi. –

2

Bu bir tam cevap, ancak geçersiz nasıl açıklayan benim yorumun sadece daha iyi bir biçimlendirilmiş versiyonu :: yenidir.

class XMLModel 
    def new *args 
    if self == XMLModel 
     klass = use_v1? ? XMLModelV1 : XMLModelV2 
     instance = klass.allocate 
     instance.initialize *args 
     instance   
    else 
     super *args 
    end 
    end 
end 
# and of course: 
class XMLModelV1 < XMLModel; end 
class XMLModelV2 < XMLModel; end