C# 设计模式-原型模式

一.介绍  

  原型模式(Prototype Pattern)。属于创建型模式。用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。

二.实现

  简单来说,原型模式可以直接复制一个现有的对象,而不需要重新new操作去创建。这种创建分两种方式,浅拷贝和深拷贝。

  1.浅拷贝

  定义一个接口IPerson来规范People。ICloneable是系统自带的接口,来定义需要用clone方法的。

public interface IPerson
{
    object Clone();
}

public class Person : IPerson, ICloneable
{
    public string Name { get; set; }
    public Address Address { get; set; }

    public override string ToString()
    {
        var newLine = Environment.NewLine;
        var indent = "\t";
        var str = $"Name:{Name}{newLine}Address:{newLine}{indent}Province:{Address.Province}{newLine}{indent}City:{Address.City}{newLine}";
        return str;
    }

    /// <summary>
    /// 浅拷贝
    /// </summary>
    /// <returns></returns>
    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

public class Address
{
    public string City { get; set; }
    public string Province { get; set; }
}

  代码实现。

public static void Main(string[] args)
{
    var person1 = new Person { Name = "aaa", Address = new Address { City = "Wuhan", Province = "HuBei" } };
    Console.WriteLine("Person1 is ");
    Console.WriteLine(person1.ToString());

    var person2 = person1.Clone() as Person;
    Console.WriteLine("Cloned Person2 is ");
    Console.WriteLine(person2.ToString());


    Console.WriteLine("============= 修改原对象 =============");
    person1.Name = "bbb";
    person1.Address.Province = "Shanghai";
    person1.Address.City = "shanghai";

    Console.WriteLine("Person1 is");
    Console.WriteLine(person1.ToString());

    Console.WriteLine("Cloned Person2 is ");
    Console.WriteLine(person2.ToString());


    Console.WriteLine("============= 修改复制对象 =============");
    person2.Name = "ccc";
    person2.Address.Province = "Guangdong";
    person2.Address.City = "GuangZhou";

    Console.WriteLine("Person1 is");
    Console.WriteLine(person1.ToString());

    Console.WriteLine("Cloned Person2 is ");
    Console.WriteLine(person2.ToString());
}

  结果如图。

   从结果可见,people修改了属性值,对people2的属性值没有影响。反过来,people2修改属性值对people也没有影响。但两者address的引用修改后,都互相影响。

  2.深拷贝

public interface IPerson
{
    object Clone();
}

[Serializable]
public class Person : IPerson, ICloneable
{
    public string Name { get; set; }
    public Address Address { get; set; }

    public override string ToString()
    {
        var newLine = Environment.NewLine;
        var indent = "\t";
        var str = $"Name:{Name}{newLine}Address:{newLine}{indent}Province:{Address.Province}{newLine}{indent}City:{Address.City}{newLine}";
        return str;
    }

    /// <summary>
    /// 深拷贝
    /// </summary>
    /// <returns></returns>
    public object Clone()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Person));
        using (var stream = new System.IO.MemoryStream())
        {
            serializer.Serialize(stream, this);
            stream.Seek(0, System.IO.SeekOrigin.Begin);
            return serializer.Deserialize(stream) as Person;
        }
    }
}

[Serializable]
public class Address
{
    public string City { get; set; }
    public string Province { get; set; }
}

  执行方法和上面一样,结果是属性值和引用值都不相互影响。通过序列化和反序列化创建了一个新的对象,这样拷贝出来的类指向就不会和原有的类一样。

三.总结

  优点:

  1.隐藏了创建实例的繁琐过程,只需要通过clone方法就能获取实例。

  2.使用拷贝代替new,减少资源损耗。

  缺点:

  需要在每个需要拷贝的类中实现clone方法。

  

posted @ 2021-01-13 14:59  shine声  阅读(309)  评论(0编辑  收藏  举报