Home  /  Questions  /  Question



50   50
Sep 20, 2010


Prototype Pattern to copy/clone objects

I would like to know why following the DOF Prototype pattern is better suited than creating a simple and plain way of copying/cloning an object.

Given the following base class and creational factory method class PersonBirthFactory:


public class Person
{
  public Object Firstname{ get; set; }
  public Object Lastname{ get; set; }
}


public class PersonBirthFactory
  {
    public static CreatePerson()
    {
       Person p = new Person();
       p.FirstName = firstName;
       p.LastName = firstName;
       return p;
    }
}
The .NETOptimized version of the Prototype uses the following code to perform a deep copy: 

public object DeepCopy()
{
   MemoryStream stream = new MemoryStream();
   BinaryFormatter formatter = new BinaryFormatter();
   formatter.Serialize(stream, this);
   stream.Seek(0, SeekOrigin.Begin);
   object copy = formatter.Deserialize(stream);
   stream.Close();
   return copy;
}


A couple questions as to why I cannot use the following as opposed to the example above:

public object DeepCopy()
{
  Person p = new Person();
  p.FirstName = this.FirstName;
  p.LastName = this.FirstName;
  return p;

}
Why not use the following logic or something more simple than messing w/ MemoryStream, Serialization, Etc?

I can implement this pattern w/o doing research and wondering the benefits here, is it just a performance increase for using this?

In my current scenario the copy might happen at most 4 times in an hour, but when it happens they happen in quick sucession. I am mainly doing this to remove the logic  when creating a collection and need to fill in the missing items(cloned from other items) from the factory. The offending code is complex if/then/else/loops/etc... Best suited outside the factory in another object where I may need to use in other parts of the application down the road.

Looking for alternatives and would like to open a discussion on the best alternative.

TIA,

S




1,128   99.9
Sep 21, 2010
Hi,

I can think of two issues with your approach of copying the object.

1. You will need to modify your copy method each time a property changes in the Person class.
2. You copy the reference, not the object. This means that when the primary object has a member
   of a reference type and it changes, your copy will change too. (will provide example shortly).

Hope that helps.

UPDATE: Added Code example

First, the Person class:
[Serializable] 
      public class Person 
      { 
          public Object FirstName { get; set; } 
          public Object LastName { get; set; } 
          public Person Mother { get; set; } 

          public static Person CreatePerson(string firstName, string lastName) 
          { 
              var p = new Person { FirstName = firstName, LastName = lastName }; 
              return p; 
          } 

          public override string ToString() 
          { 
              if( Mother != null) 
              { 
                  return string.Format("{0}, {1} (Mother: {2})", LastName, FirstName, Mother); 
              } 
              else
              { 
                  return string.Format("{0}, {1})", LastName, FirstName); 
              } 
          } 
      } 


Helper methods for copying:
public static class PersonBirthFactory 
     { 
         public static Person DeepCopy(this Person person) 
         { 
             var stream = new MemoryStream(); 
             var formatter = new BinaryFormatter(); 

             formatter.Serialize(stream, person); 
             stream.Seek(0, SeekOrigin.Begin); 

             object copy = formatter.Deserialize(stream); 
             stream.Close(); 

             return copy as Person; 
         } 

         public static Person SimpleCopy(this Person person) 
         { 
             var p = new Person {FirstName = person.FirstName, LastName = person.LastName, Mother =  person.Mother}; 
             return p; 
         } 
     } 
Sample Console Application:

 
internal class Program 
    { 
        private static void Main(string[] args) 
        { 
            var john = Person.CreatePerson("John", "Doe"); 
            john.Mother = Person.CreatePerson("Jane", "Doe"); 
            //var jane = Person.CreatePerson("Jane", "Doe");

            var johnSimpleCopy = john.SimpleCopy(); 
            var johnDeepCopy = john.DeepCopy(); 


            System.Console.WriteLine("============{STEP 1}=="); 
            System.Console.WriteLine(john); 
            System.Console.WriteLine(johnSimpleCopy); 
            System.Console.WriteLine(johnDeepCopy); 

            john.Mother.FirstName = "Jen"; 
          
            System.Console.WriteLine("============{STEP 2}=="); 
            System.Console.WriteLine(john); 
            System.Console.WriteLine(johnSimpleCopy); 
            System.Console.WriteLine(johnDeepCopy); 
        } 
    } 

 The output:

==================={STEP 1}==
Doe, John (Mother: Doe, Jane))
Doe, John (Mother: Doe, Jane))
Doe, John (Mother: Doe, Jane))
==================={STEP 2}==
Doe, John (Mother: Doe, Jen))
Doe, John (Mother: Doe, Jen))
Doe, John (Mother: Doe, Jane))


As you can see from above, when chaning the Mother in
object "john" "johnsimplecopy" is also changed. This means
that your version of the copying only copies the reference
not the object itself.


 1 comment
 
Hi Robert, I would like to suggest one thing in SimpleCopy Method. public static Person SimpleCopy(this Person person) { var p = new Person {FirstName = person.FirstName, LastName = person.LastName, Mother = person.Mother}; return p; } Here Mother is object of Person class. So, you should name new object of mother when you are doing clone in simple copy. If we do that then it will be new object not reference. public Person(string fName, string lName, Person mother) { firstName = fName; lastName = lName; Mother = new Person(mother.firstName, mother.lastName); } --- Nikhil Contractor  Oct 05, 2010

50   50
Oct 01, 2014
Thanks for this. Just replicated it and got:
==================={STEP 1}== Doe, John (Mother: Doe, Jane)) Doe, John (Mother: Doe, Jane)) Doe, John (Mother: Doe, Jane)) ==================={STEP 2}== Doe, John (Mother: Doe, Jen)) Doe, John (Mother: Doe, Jen)) Doe, John (Mother: Doe, Jane))

Thanks, Richard Wilcox

50   50
Mar 10, 2015
Thanks a lot I did exactly as you said and it worked just amazing, see my output Thanks,

==================={STEP 1}==

Doe, John (Mother: Doe, Jane))

Doe, John (Mother: Doe, Jane))

Doe, John (Mother: Doe, Jane))

==================={STEP 2}==

Doe, John (Mother: Doe, Jen))

Doe, John (Mother: Doe, Jen))

Doe, John (Mother: Doe, Jane))