Short version of the question: What is a proper way to implement object cloning with deep copy, using generally accepted OOP principles?
I ran into this while looking into the Prototype Design Pattern in the GoF Design Patterns book, but I think it applies to general object cloning.
Wouldn't it be, each class has to properly implement its own instance method of deep_copy
, because each class has its own way to "going through" all elements, such as left
and right
for a binary tree, and sometimes, an object A having 2 other references to 2 other objects: B and C, may mean A own B and C, and therefore B and C should also be cloned, while in some cases, such as a node object in a graph, A having a reference to B and C just means it is pointing to B and C and DO NOT own B, C (other nodes in the graph may also point to B and C).
There is a way to clone, which is serialize it and unserialize it (which should be same as data marshalling?) but it doesn't handle the case when the object doesn't own another object, or in the case of a node in a graph, can you serialize and unserialize, and get back a cloned node that points to the proper nodes in the graph as the original node object does?
Another complication may arise, if object A has an instance variable foo
, and it has a data structure that reference object B
twice, so we really should not clone B twice. Or, if foo
reference it once in its data structure, but another instance variable bar
also reference B
, then also we should not clone B twice but once. And if A doesn't own B, then we should not clone B at all.
But let's say we ignore the complication above:
Then roughly speak, all classes in your application should implement its own method of deep_copy
, and it roughly is this:
# Pseudo code:
class SomeClass
def deep_copy
new_object = self.clone() # to have all the instance variables and
# methods cloned, but just a shallow copy, and
# also, all the inheritance, access to
# class variables, methods, and inheritance
# hierarchy should be properly set up
for all objects that is referenced by my instance variables
if I own the object (by the design of my class), then
# rely on polymorphism to make a proper deep_copy of this object
new_object.this_instance_variable = self.this_instance_variable.deep_copy()
end
end
return new_object
end
end
and depending on whether the primitive types are object or not, it may just say: if I own the object, but it is primitive, then don't clone it. Or in case the primitive types (like Fixnum, 1, 2, 3) are objects too, as in Ruby, then just let it clone it (because you don't want to do type checking to see whether it is clone-able), but in the self.clone
line, it will raise an exception to say that this type is not for cloning, and in that case, just catch the exception and return the same object without cloning it (which is the base case of the recursion).
But the key point is, using generally accepted OOP principles, every class in your app has to have the deep_copy
implemented, and its contract (the interface contract) is that it will indeed return a clone of "myself" together with deep copies of objects that I own (recursively). And it may be difficult because a lot of times, we define a class, and we don't really implement a deep_copy
. If our app has 12 classes, and we need a clone with deep copy, then we actually have to implement such clone with deep copy for all 12 classes (or for all classes that may need to participate in the deep copy). Is the above correct, or are there some corrections according to OOP principles?
deep_copy
for immutable classes (especially in languages with a garbage collector). When doing a deep copy for a class with an immutable member, you can just pass a reference of the member info the copy.