2017-07-08 1 views
2

zu erstellen Ich habe 3 einfache Klassen CashRegister, Bill und Position. Ein CashRegister besteht aus Bill-Objekten und ein Bill-Objekt besteht aus Position-Objekten. Sie sind wie folgtMethoden, um tiefe Kopie von Objekten ohne die Hilfe von Marshal

implementiert
class CashRegister 
    def initialize 
    @bills = [] 
    end 

    def clone 
    #? 
    end 
end 

class Bill 
    def initialize(nr) 
    @nr = nr 
    @positions = [] 
    end 

    def clone 
    #? 
    end 
end 

class Position 
    def initialize(product, price) 
    @product = product 
    @price = price 
    end 

    def clone 
    #? 
    end 
end 

Wie kann ich Methoden erstellen, die tief die Objekte dieser Klassen kopieren. Die Verwendung von Marshal.load(Marshal.dump(an_obj)) ist nicht erlaubt.

Edit: Bisher habe ich diese bekam:

class CashRegister 
     def initialize 
     @bills = [] 
     end 

     def clone 
     @bills.map { |bill| bill.clone} 
     end 
    end 

    class Bill 
     def initialize(nr) 
     @nr = nr 
     @positions = [] 
     end 

     def clone 
     cloned = super 
     cloned.positions = @positions.map{ |pos| pos.clone}  
     cloned 
     end 
    end 

    class Position 

     attr_reader :preis 
     # this method is given 
     def produkt 
     @produkt.clone() 
     end 

     def initialize(product, price) 
     @product = product 
     @price = price 
     end 

     def clone 
     cloned = super 
     cloned.product  
     cloned 
     end 
    end 

Der Klon-Methode in der Klasse Position scheint ok (kein Compiler-Fehler) zu sein. Aber es gibt einen Fehler in der Klasse Bill, es heißt "undefined method 'positions =', also muss das Problem in der Zeile sein cloned.positions = @positions.map{ |pos| pos.clone}. Aber ich verstehe nicht, können wir cloned.positions nicht so anrufen?

Antwort

1

arbeitet Diese Lösung

class CashRegister 
    attr_accessor :bills  

    def initialize 
    @bills = [] 
    end 

    def clone 
    cloned = super 
    cloned.bills = @bills.map { |bill| bill.clone } 
    cloned 
    end 
end 

class Bill 
    attr_accessor :positions 

    def initialize(nr) 
    @nr = nr 
    @positions = [] 
    end 

    def clone 
    cloned = super 
    cloned.positions = @positions.map{ |pos| pos.clone }  
    cloned 
    end 
end 

class Position 
    attr_reader :price 
    attr_writer :product 

    # this method is given 
    def product 
    @product.clone 
    end 

    def initialize(product, price) 
    @product = product 
    @price = price 
    end 

    def clone 
    cloned = super 
    cloned.product = product 
    cloned 
    end 
end 
2

Es ist nur die Instanzvariablen Sie kümmern.

class Position 
    attr_accessor :product, :price 
    def initialize(product, price) 
    @product = product 
    @price = price 
    end 
end 

p1 = Position.new("lima beans", 2.31) 
    #=> #<Position:0x000000027587b0 @product="lima beans", @price=2.31> 
p2 = Position.new(p1.product, p1.price) 
    #=> #<Position:0x0000000273dd48 @product="lima beans", @price=2.31> 

Wir können bestätigen, dass p2 eine tiefe Kopie von p1 ist.

p1.product = "lettuce" 
p1.price = 1.49 

p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49> 
p2 #=> #<Position:0x000000026e9e00 @product="lima beans", @price=2.31> 

p2.product = "spinach" 
p2.price = 2.10 

p1 #=> #<Position:0x0000000271f870 @product="lettuce", @price=1.49> 
p2 #=> #<Position:0x000000026e9e00 @product="spinach", @price=2.1> 

Es ist komplexer, wenn zum Beispiel waren die Klasse wie folgt definiert (wobei products ein Array ist).

p1 = Position.new ["carrots", "onions"] 
    #=> #<Position:0x000000025b8928 @products=["carrots", "onions"]> 
p2 = Position.new p1.products 
    #=> #<Position:0x000000025b0048 @products=["carrots", "onions"]> 

p1.products << "beets" 

p1 #=> #<Position:0x000000025b8928 @products=["carrots", "onions", "beets"]> 
p2 #=> #<Position:0x000000025b0048 @products=["carrots", "onions", "beets"]> 

p2 ist nicht was wir wollen. Wir würden

p1 = Position.new ["carrots", "onions"] 
    #=> #<Position:0x00000002450900 @products=["carrots", "onions"]> 
p2 = Position.new p1.products.dup 
    #=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]> 

(beachten Sie die .dup) schreiben müssen, so dass

p1.products << "beets" 
    #=> ["carrots", "onions", "beets"] 

p1 #=> #<Position:0x00000002450900 @products=["carrots", "onions", "beets"]> 
p2 #=> #<Position:0x0000000243aa88 @products=["carrots", "onions"]> 

Generell müssen wir tiefe Kopien der Instanzvariablen machen.

0

Eine andere mögliche Antwort ist die full_dup Juwel (vollständige Offenlegung, von mir geschrieben) zu verwenden, dann verwenden Sie einfach:

p2 = p1.full_dup 

Jetzt full_dup, wie regelmäßige dup hat keine Singleton-Methoden nicht kopieren. Wenn das wichtig ist, probiere stattdessen den full_clone-Edelstein (yup, bei mir).

Wenn Felder vom dup (oder Klonprozess) ausgeschlossen werden müssen, kann die optionale Methode full_dup_exclude (oder full_clone_exclude) definiert werden, um Felder aufzulisten, die von der Verarbeitung ausgeschlossen werden sollen.

Beachten Sie, dass Sie sich keine Gedanken darüber machen müssen, ob Sie versuchen, Zahlen, Symbole und andere nicht klonbare Dinge zu klonen, die in Ihrem Objekt vorhanden sein können. Diese werden sicher von den Edelsteinen gehandhabt.

Verwandte Themen