设计模式学习之原型模式(Prototype,创建型模式)(5)-LMLPHP

通过序列化的方式实现深拷贝

    [Serializable]
public class Person:ICloneable
{
public string Name { get; set; }
public int Age { get; set; }
public List<Friend> FriendList { get; set; }
public object Clone()
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this);
memoryStream.Position = ;
Person p = (Person)formatter.Deserialize(memoryStream);
return p;
}
}
[Serializable]
public class Friend
{
public string Name { get; set; }
public int Age { get; set; }
}

在开发中如果我们希望快速的创建一个对象,并且该对象和原有的对象拥有相同的数据,并且和原有的对象不相干,那么我们就可以这样做

第一步:

假如我需要快速创建一个Person对象,然后和某个Person对象相同,如果我们我们只需要Person对象中的属性不引用其他数据信息,可以使用浅拷贝;

如果我们需要Person对象中所有的信息,包括引用的数据信息,可以使用深拷贝

第二步:

在Person类中实现Cloneable接口,重写clone()方法,如果是浅拷贝,只需要直接调用父类的clone()方法就行,如果是深拷贝,需要在clone()方法中重新开辟引用字段所需的内存

代码如下:

Person.java

package com.designpattern.prototype;

import java.util.ArrayList;
import java.util.List; public class Person implements Cloneable {
private String name;
private int age; //朋友
private List<String> friends; public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} /**
* 实现浅拷贝
*/
// protected Person clone(){
//
// try {
// return (Person)super.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// return null;
// }
//
// } /**
* 实现深拷贝
*/
protected Person clone(){ try {
List<String> newfriends = new ArrayList<String>();
for (String friend : this.getFriends()) {
newfriends.add(friend);
}
Person person = (Person)super.clone();
person.setFriends(newfriends);
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
} }
}

MainClass.java

package com.designpattern.prototype;

import java.util.ArrayList;
import java.util.List; public class MainClass { public static void main(String[] args) {
//假如我需要快速创建一个Person对象,然后和某个Person对象相同,如果我们我们只需要Person对象中的属性不引用其他数据信息,可以使用浅拷贝
//如果我们需要Person对象中所有的信息,包括引用的数据信息,可以使用深拷贝
/*
* 浅拷贝
*/
// Person person = new Person();
// person.setName("jack");
// person.setAge(18);
//
// Person person2 = person.clone();//相当于重新开辟一块内存空间,和person互不干扰
// person2.setName("jack1");
//
// System.out.println(person.getName());
// System.out.println(person2.getName()); Person person = new Person();
person.setName("jack");
person.setAge();
List<String> friends = new ArrayList<String>();
friends.add("p1");
friends.add("p2");
person.setFriends(friends); Person person2 = person.clone();
person2.setName("jack1");
friends.add("p3");//person 引用friends,friends改变,person的friends就会改变,如果用浅拷贝,person2也会跟着改变
//如果用深拷贝,person2不会跟着改变,因为person2的friends和person的friends没有指向同一块内存 System.out.println(person.getName());
System.out.println(person2.getName());
System.out.println(person.getFriends());
System.out.println(person2.getFriends());
} }

一、什么是原型模式

Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。

二、原型模式的特点

1. 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。

2.目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。

3.根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

三、原型模式应用场景

- 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。

- 希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)。

- 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。

.Net Framework源代码中的模式之Prototype(原型模式)

转载地址:http://kb.cnblogs.com/page/68814/

  用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

设计模式学习之原型模式(Prototype,创建型模式)(5)-LMLPHP

  以.NET Framework 2.0 System.Collections中类为例。

设计模式学习之原型模式(Prototype,创建型模式)(5)-LMLPHP  System.Collections. ICollection

public interface ICollection : IEnumerable
{
}

  System.Collections. ICloneable

public interface ICloneable
{
  object Clone();
}

  System.Collections. Stack

public class Stack : ICollection, ICloneable
{
  public virtual Object Clone()
  {
    Stack s = new Stack(_size);
    s._size = _size;
    Array.Copy(_array, 0, s._array, 0, _size);
    s._version = _version;
    return s;
  }
}

 

  System.Collections. Queue

public class Queue : ICollection, ICloneable
{
  public virtual Object Clone()
  {
   Queue q = new Queue(_size);
   q._size = _size;
   int numToCopy = _size;
   int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
   Array.Copy(_array, _head, q._array, 0, firstPart);
   numToCopy -= firstPart;
   if (numToCopy > 0)
   Array.Copy(_array, 0, q._array, _array.Length - _head, numToCopy);
   q._version = _version;
   return q;
  }
}

  调用代码

public class Client
{
  public static void Main()
  {
    Stack myStack = new Stack();
    myStack.Push("Hello");
    myStack.Push("World");
    myStack.Push("!");
    Stack myStackCopy = (Stack)myStack.Clone(); 
    foreach (string s in myStackCopy)
    {
      Console.Write(s);
    }
    Console.WriteLine();
    Console.ReadLine();
  }
}

 

  在.NET Framework中,可以通过实现ICloneable接口来实现原型模式,ICloneable接口只有一个Clone方法。克隆的实现方法有两种:浅拷贝(shallow copy)与深拷贝(deep copy)。

  浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。

  对于值类型,浅拷贝通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中;深拷贝和浅拷贝相同,通过赋值等操作直接实现,将对象中的值类型的字段拷贝到新的对象中。 对于引用类型,浅拷贝通过MemberwiseClone 方法创建一个浅副本,方法是创建一个新对象,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用原始对象,与原对象引用同一对象;深拷贝拷贝对象应用,也拷贝对象实际内容,也就是创建了一个新的对象,改变新对象不会影响到原始对象的内容。

  在下列情况下,应当使用Prototype模式:

  • 当一个系统应该独立于它的产品创建,构成和表示时;
  • 当要实例化的类是在运行时刻指定时,例如,通过动态装载;
  • 为了避免创建一个与产品类层次平行的工厂类层次时;
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
05-11 11:22