原型模式

  • 原型模式-介绍
  • 原型模式-参数详解
  • 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";
        }
    }

}