Autumn SALE
Prototype

Prototype を Ruby で

Prototype 生成に関するデザインパターンの一つで 特定のクラスに結合することなく オブジェクト たとえ複雑なオブジェクトでも のクローン作成を可能とします

プロトタイプのクラス全部には 共通するインターフェースが必要です これにより 具象クラスが不明であってもオブジェクトを複製することが可能となります プロトタイプ・オブジェクトが 完全なコピーを生成できるのは 同じクラスのオブジェクト同士が非公開フィールドを互いにアクセスできるからです

複雑度

人気度

使用例 Prototype パターンは Ruby では dup または clone メソッドを使って 初めから利用可能です

見つけ方 このパターンは clonecopy といったメソッドで容易に識別可能です

概念的な例

この例は Prototype デザインパターンの構造を説明するためのものです 以下の質問に答えることを目的としています

  • どういうクラスからできているか
  • それぞれのクラスの役割は
  • パターンの要素同士はどう関係しているのか

main.rb: 概念的な例

# The example class that has cloning ability. We'll see how the values of field
# with different types will be cloned.
class Prototype
  attr_accessor :primitive, :component, :circular_reference

  def initialize
    @primitive = nil
    @component = nil
    @circular_reference = nil
  end

  # @return [Prototype]
  def clone
    @component = deep_copy(@component)

    # Cloning an object that has a nested object with backreference requires
    # special treatment. After the cloning is completed, the nested object
    # should point to the cloned object, instead of the original object.
    @circular_reference = deep_copy(@circular_reference)
    @circular_reference.prototype = self
    deep_copy(self)
  end

  # deep_copy is the usual Marshalling hack to make a deep copy. But it's rather
  # slow and inefficient, therefore, in real applications, use a special gem.
  private def deep_copy(object)
    Marshal.load(Marshal.dump(object))
  end
end

class ComponentWithBackReference
  attr_accessor :prototype

  # @param [Prototype] prototype
  def initialize(prototype)
    @prototype = prototype
  end
end

# The client code.
p1 = Prototype.new
p1.primitive = 245
p1.component = Time.now
p1.circular_reference = ComponentWithBackReference.new(p1)

p2 = p1.clone

if p1.primitive == p2.primitive
  puts 'Primitive field values have been carried over to a clone. Yay!'
else
  puts 'Primitive field values have not been copied. Booo!'
end

if p1.component.equal?(p2.component)
  puts 'Simple component has not been cloned. Booo!'
else
  puts 'Simple component has been cloned. Yay!'
end

if p1.circular_reference.equal?(p2.circular_reference)
  puts 'Component with back reference has not been cloned. Booo!'
else
  puts 'Component with back reference has been cloned. Yay!'
end

if p1.circular_reference.prototype.equal?(p2.circular_reference.prototype)
  print 'Component with back reference is linked to original object. Booo!'
else
  print 'Component with back reference is linked to the clone. Yay!'
end

output.txt: 実行結果

Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!

他言語での Prototype

Prototype を C# で Prototype を C++ で Prototype を Go で Prototype を Java で Prototype を PHP で Prototype を Python で Prototype を Rust で Prototype を Swift で Prototype を TypeScript で