Prototyp To kreacyjny wzorzec projektowy pozwalający klonować obiekty — również te złożone — bez konieczności sprzęgania z ich klasami.
Wszystkie klasy prototyp powinny mieć wspólny interfejs który pozwoli kopiować ich obiekty nawet gdy nie zna się ich konkretnych klas. Obiekty-prototypy mogą tworzyć kompletne kopie, ponieważ pola prywatne danej klasy są dostępne dla innych obiektów tej samej klasy.
Złożoność:
Popularność:
Przykłady użycia: Wzorzec Prototyp jest dostępny w Ruby od razu — dzięki metodom dup
lub clone
.
Identyfikacja: Prototyp można łatwo poznać dzięki obecności metod clone
lub copy
, itp.
Przykład koncepcyjny
Poniższy przykład ilustruje strukturę wzorca projektowego Prototyp ze szczególnym naciskiem na następujące kwestie:
Z jakich składa się klas?
Jakie role pełnią te klasy?
W jaki sposób elementy wzorca są ze sobą powiązane?
main.rb: Przykład koncepcyjny
# 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: Wynik działania
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!
Prototyp w innych językach