2017-07-08 56 views
2

私は3つの単純なクラスCashRegister、BillとPositionを持っています。 CashRegisterはBillオブジェクトで構成され、BillオブジェクトはPositionオブジェクトで構成されます。それらは次のように実装されていますマーシャリングの助けを借りずにオブジェクトのディープコピーを作成するメソッド

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 

これらのクラスのオブジェクトをディープコピーできるメソッドを作成する方法を教えてください。 Marshal.load(Marshal.dump(an_obj))の使用は許可されていません。

編集:これまでのところ、私はこれを持っている:

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 

クラスのポジションでcloneメソッドは、(なしコンパイルエラー)OKならないようです。しかし、クラスビルのエラーには「未定義のメソッドの位置=」というエラーがありますので、問題は行cloned.positions = @positions.map{ |pos| pos.clone}にある必要がありますが、わかりません。cloned.positionsはそのように呼び出すことはできませんか?

答えて

1

このソリューションは、動作します

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

それはあなたが心配する必要は単にインスタンス変数です。

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> 

我々はp2p1のディープコピーであることを確認することができます。

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> 

例えば、クラスがあったが、あればそれはもっと複雑です以下のように定義される(productsは配列です)。

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

私たちが望むものではありません。私たちは、

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

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

は、より一般的に、我々はインスタンス変数の深いコピーを作成する必要が

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

.dupに注意してください)

ように記述する必要があります。

p2 = p1.full_dup 

今すぐfull_dup、通常のDUPのように、任意の特異メソッドをコピーしません:

0

別の可能な答えは(私が書いた完全な開示、)full_dup宝石、単に使用を使用することです。それが重要なのであれば、代わりにfull_clone gemを試してみてください。

dup(またはクローンプロセス)から除外する必要のあるフィールドがある場合、オプションのfull_dup_exclude(またはfull_clone_exclude)メソッドを定義して、処理から除外するフィールドをリストすることができます。

注:オブジェクトに存在する可能性のある数字、記号、その他のクローン不可能なものを複製しようとする心配はありません。これらは安全に宝石として扱われます。

関連する問題