原型模式
- 原型模式-介绍
- 原型模式-参数详解
- Object.MemberwiseClone 方法
- 示例:
- 注解
- 原型模式
- 原型模式-案例1
- 原型模式-案例2
原型模式-介绍
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式-参数详解
- Participants
The classes and objects participating in this pattern are:
- Prototype (ColorPrototype)
declares an interface for cloning itself
- ConcretePrototype (Color)
implements an operation for cloning itself
- Client (ColorManager)
creates a new object by asking a prototype to clone itself
Object.MemberwiseClone 方法
创建当前 Object 的浅表副本。
protected object MemberwiseClone ();
- 返回 Object
当前 Object 的浅表副本。
示例:
下面的示例演示 MemberwiseClone 方法。 它定义了一 ShallowCopy 种方法,该方法调用MemberwiseClone 方法以对对象执行浅表复制操作 Person 。
它还定义了对 DeepCopy 对象执行深层复制操作的方法 Person 。
using System;
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person) this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
}
}
public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565);
// Perform a shallow copy of p1 and assign it to p2.
Person p2 = p1.ShallowCopy();
// Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
}
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
- 在此示例中, Person.IdInfo 属性返回 IdInfo 对象。
如示例的输出所示,当 Person 通过调用方法克隆对象时, MemberwiseClone 克隆的 Person对象是原始对象的独立副本,只不过它们共享相同的 Person.IdInfo 对象引用。
因此,修改克隆的 Person.IdInfo属性会更改原始对象的 Person.IdInfo 属性。另一方面,执行深层复制操作时, Person 可以修改克隆的对象(包括其
Person.IdInfo 属性),而不会影响原始对象。
注解
方法创建一个 MemberwiseClone 浅表副本,方法是创建一个新的对象,然后将当前对象的非静态字段复制到新的对象。
- 如果字段是值类型,则执行字段的逐位副本。
- 如果字段是引用类型,则会复制引用,但不会复制引用的对象;因此,原始对象及其复本引用相同的对象。
例如,假设有一个名为 X 的对象引用对象 A 和 B。对象 B 反过来引用对象 C。X 的浅表副本创建新的对象 X2,后者同时引用对象 A 和 B。
与之相比,X 的深层副本会创建一个新的对象 X2,该对象引用作为 A 和 B 的副本的新对象 A2 和 B2,进而引用新的对象 C2,这是 C 的副本。该示例说明了浅层和深层复制操作之间的差异。
如果方法执行的浅层复制操作 MemberwiseClone 不能满足您的需要,可以通过多种方式实现深层复制操作。 这些功能包括以下这些:
调用要复制的对象的类构造函数,以创建具有从第一个对象获取的属性值的第二个对象。 这假设对象的值由其类构造函数完全定义。
调用 MemberwiseClone 方法以创建对象的浅表副本,然后将新对象的值与原始对象的值相同,分配给任何属性或其值为引用类型的字段。
该 DeepCopy 示例中的方法演示了这种方法。序列化要深层复制的对象,然后将序列化的数据还原到其他对象变量。 使用带有递归的反射来执行深层复制操作。
原型模式
//-------------------------------------------------------------------------------------
// PrototypeStructure.cs
//-------------------------------------------------------------------------------------
using UnityEngine;
using System.Collections;
public class PrototypeStructure : MonoBehaviour
{
void Start( )
{
// Create two instances and clone each
ConcretePrototype1 p1 = new ConcretePrototype1("I");
ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
Debug.Log("Cloned: "+c1.Id);
ConcretePrototype2 p2 = new ConcretePrototype2("II");
ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
Debug.Log("Cloned: "+c2.Id);
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
abstract class Prototype
{
private string _id;
// Constructor
public Prototype(string id)
{
this._id = id;
}
// Gets id
public string Id
{
get { return _id; }
}
public abstract Prototype Clone();
}
/// <summary>
/// A 'ConcretePrototype' class
/// </summary>
class ConcretePrototype1 : Prototype
{
// Constructor
public ConcretePrototype1(string id)
: base(id)
{
}
// Returns a shallow copy
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
/// <summary>
/// A 'ConcretePrototype' class
/// </summary>
class ConcretePrototype2 : Prototype
{
// Constructor
public ConcretePrototype2(string id)
: base(id)
{
}
// Returns a shallow copy
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
原型模式-案例1
//-------------------------------------------------------------------------------------
// PrototypePatternExample1.cs
//-------------------------------------------------------------------------------------
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//This real-world code demonstrates the Prototype pattern in which new Color objects are created by copying pre-existing, user-defined Colors of the same type.
namespace PrototypePatternExample1
{
public class PrototypePatternExample1 : MonoBehaviour
{
void Start()
{
ColorManager colormanager = new ColorManager();
// Initialize with standard colors
colormanager["red"] = new Color(255, 0, 0);
colormanager["green"] = new Color(0, 255, 0);
colormanager["blue"] = new Color(0, 0, 255);
// User adds personalized colors
colormanager["angry"] = new Color(255, 54, 0);
colormanager["peace"] = new Color(128, 211, 128);
colormanager["flame"] = new Color(211, 34, 20);
// User clones selected colors
Color color1 = colormanager["red"].Clone() as Color;
Color color2 = colormanager["peace"].Clone() as Color;
Color color3 = colormanager["flame"].Clone() as Color;
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
class Color : ColorPrototype
{
private int _red;
private int _green;
private int _blue;
// Constructor
public Color(int red, int green, int blue)
{
this._red = red;
this._green = green;
this._blue = blue;
}
// Create a shallow copy
public override ColorPrototype Clone()
{
Debug.Log("Cloning color RGB: (" + _red + " ," + _green + "," + _blue + ")");
return this.MemberwiseClone() as ColorPrototype;
}
}
/// <summary>
/// Prototype manager
/// </summary>
class ColorManager
{
private Dictionary<string, ColorPrototype> _colors = new Dictionary<string, ColorPrototype>();
// Indexer
public ColorPrototype this[string key]
{
get { return _colors[key]; }
set { _colors.Add(key, value); }
}
}
}
原型模式-案例2
//-------------------------------------------------------------------------------------
// PrototypePatternExample2.cs
//-------------------------------------------------------------------------------------
using UnityEngine;
using System.Collections;
using System;
namespace PrototypePatternExample2
{
public class PrototypePatternExample2 : MonoBehaviour
{
void Start()
{
CloneFactory factory = new CloneFactory();
Sheep sally = new Sheep();
Sheep clonedSheep = (Sheep)factory.GetClone(sally);
Debug.Log("Sally: " + sally.ToStringEX());
Debug.Log("Clone of Sally: " + clonedSheep.ToStringEX());
Debug.Log("Sally Hash: " + sally.GetHashCode() + " - Cloned Sheep Hash: " + clonedSheep.GetHashCode());
}
}
public class CloneFactory
{
public IAnimal GetClone(IAnimal animalSample)
{
return (IAnimal)animalSample.Clone();
}
}
public interface IAnimal : ICloneable
{
object Clone();
}
public class Sheep : IAnimal
{
public Sheep()
{
Debug.Log("Made Sheep");
}
public object Clone()
{
Sheep sheep = null;
try
{
sheep = (Sheep)base.MemberwiseClone();
}
catch (Exception e)
{
Debug.LogError("Error cloning Sheep");
}
return sheep;
}
public string ToStringEX()
{
return "Hello I'm a Sheep";
}
}
}