用心理解设计模式——原型模式 (Prototype Pattern)

前置文章: 用心理解设计模式——设计模式的原则 

设计模式相关代码已统一放至 我的 Github

一、定义

  建造型模式之一。

  Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

  (用原型实例指定要创建对象的种类,并通过拷贝此原型创建新的对象)

二、结构解析

  原型模式的一般结构有两种角色:抽象原型、具体原型。

  抽象原型类,声明Clone自身的接口方法;

  具体原型类,实现Clone自身的接口方法。

扫描二维码关注公众号,回复: 4174666 查看本文章

三、评价

  原型模式比较简单。它提供了一个克隆自身的接口方法, 让一些具体类去实现自身的克隆操作,这样就可以通过具体类生成自身的克隆实例。

  需要借助 C# Object对象的MemberwiseClone方法。注意它是浅拷贝的。

  注意区分深拷贝和浅拷贝:

浅拷贝,基础类型按位复制(产生新的成员变量),引用类型创建一个新的引用,并让这个引用指向原引用指向的对象。

深拷贝,基础类型按位复制,引用类型以该引用指向的对象的值为构造参数构造一个新的对象,并创建一个新的引用指向这个心的对象。

  注意 string类型的特殊性! 它虽然不是基础类型,但具有基础类型的性质。这个之后有时间要另开一篇文章整理。

四、实现

using System;
using UnityEngine;

namespace Prototype
{
    //辅助测试成员类
    public class Extra
    {
        public int id;
        public string name;
        public Extra(int id, string name)
        {
            this.id = id; this.name = name;
        }
    }

    //抽象原型,提供抽象的拷贝接口方法
    public abstract class Prototype
    {
        public abstract Prototype ShallowClone();
        public abstract Prototype DeepClone();
    }

    //具体原型,实现拷贝方法
    public class ConcretePrototype : Prototype
    {
        public int id = 1;
        public string name = "A";
        public Extra extra = new Extra(1, "A");

        public override Prototype ShallowClone()
        {
            return (ConcretePrototype)this.MemberwiseClone();
        }

        public override Prototype DeepClone()
        {
            //先浅拷贝
            ConcretePrototype p = (ConcretePrototype)this.MemberwiseClone();
            //再处理引用类型成员新建处理。 以当前成员新new出来,或 在该引用类型中也实现深拷贝方法,然后调用。
            p.extra = new Extra(this.id, this.name);
            //这句其实可以不需要,因为虽然String不是基础成员,但因为其为静态常量,所以具有基础成员的性质。
            p.name = String.Copy(this.name);
            return p;
        }
    }

    public class Client
    {
        static public void Main()
        {
            ShallowCloneTest();
            Debug.Log("---------------------------------");
            DeepCloneTest();
        }

        static private void ShallowCloneTest()
        {
            //创建原型 a, 并浅拷贝为 b。
            ConcretePrototype a = new ConcretePrototype();
            ConcretePrototype b = (ConcretePrototype)a.ShallowClone();

            Debug.Log(a.id + ", " + a.name + ", " + a.extra.id + ", " + a.extra.name);   //1, A, 1, A
            Debug.Log(b.id + ", " + b.name + ", " + b.extra.id + ", " + b.extra.name);   //1, A, 1, A

            //尝试修改b
            b.id = 2;
            b.name = "B";
            b.extra.id = 2;
            b.extra.name = "B";

            //B正常,全部被修改
            //A的基础类型成员(string不是基础成员,但具有基础成员的性质)没有被修改(正常)。但引用类型成员被修改(因为浅拷贝的缘故)
            Debug.Log(a.id + ", " + a.name + ", " + a.extra.id + ", " + a.extra.name);   //1, A, 2, B
            Debug.Log(b.id + ", " + b.name + ", " + b.extra.id + ", " + b.extra.name);   //2, B, 2, B
        }

        static private void DeepCloneTest()
        {
            //创建原型 a, 并浅拷贝为 b。
            ConcretePrototype a = new ConcretePrototype();
            ConcretePrototype b = (ConcretePrototype)a.DeepClone();

            Debug.Log(a.id + ", " + a.name + ", " + a.extra.id + ", " + a.extra.name);   //1, A, 1, A
            Debug.Log(b.id + ", " + b.name + ", " + b.extra.id + ", " + b.extra.name);   //1, A, 1, A

            //尝试修改b
            b.id = 2;
            b.name = "B";
            b.extra.id = 2;
            b.extra.name = "B";

            //B正常,全部被修改。
            //A正常,没有因为B的修改而被修改。
            Debug.Log(a.id + ", " + a.name + ", " + a.extra.id + ", " + a.extra.name);   //1, A, 1, A
            Debug.Log(b.id + ", " + b.name + ", " + b.extra.id + ", " + b.extra.name);   //2, B, 2, B
        }
    }
}

猜你喜欢

转载自blog.csdn.net/NRatel/article/details/84255899
今日推荐