• 设计模式(二)-创建者模式(4)-原型模式


    一、为何需要原型模式(Prototype Pattern)?

    软件设计中,我们会遇到到这样的情况:对原对象进行拷贝一个新的副本。想要实现这样的逻辑,有一种笨方法就是对原对象里的所有变量进行逐一赋值。但是这样的做法会导致代码臃肿,逻辑复杂,还可能会有遗漏某些变量没有被赋值的问题。

    为了解决这个在代码中对每一个变量进行赋值的问题,同时又保证能够实现拷贝的功能,于是原型模式就出来了。

    定义: 用一个已经创建的实例作为原型,来创建一个与原型对象相同的新对象

    【角色】

    • 抽象原型类: 规定具体原型对象必须实现的clone()方法
    • 实现原型类: 实现抽象原型类的clone()方法。

    原型模式分为浅克隆和深克隆

    浅克隆(浅拷贝):创建一个新的对象,新对象的属性和原型对象的完全相同。对对象里的引用类型成员,仍指向原来所指向的内存地址。(这里属性指的是:值类型。同下)

    深克隆(深拷贝):创建一个新对象,对对象里的属性和引用类型成员都会被克隆,引用类型成员不再指向原来的地址。

    应用条件:

    • 对象里有非常多成员,尤其该对象的引用类型成员里还有其他的引用类型对象。

    二、例子

    需求:
    假设有一盏灯A,然后另一盏灯B根据A灯的样子造出来的。可以说这两盏灯外观一摸一样。在黑暗中,要想实现一个能有照明系统的用途,这两盏灯还需要连接一块电池才能发光照明。

    假定电池为引用类型成员,A灯和B灯属于值类型成员。
    A灯+电池 = 原对象。
    B灯 +电池 = 新对象。

    现有两种情况可以选择:
    1)情况(浅拷贝):为了节约电池的成本,把这两盏灯都连接在同一块电池。
    2)情况(深拷贝):为了这两盏灯要完全分开互不影响,一盏灯连接一块电池,所以需要两块容量一致的电池。

    Serializable: 序列化,只对深拷贝有作用。系统遍历原对象里所有引用类型成员进行逐一克隆,无需代码来处理具体的过程。被标记为 Serializable 的类才能够使用深拷贝机制,否则程序运行会崩溃。

    
       //引用类型:电池类
        [Serializable]
        public class Battery
        {
            public int Capacity;
        }
    
        //灯的原型抽象类
        [Serializable]
        public abstract class LampPrototype
        {
            public abstract int Use();
    
            public abstract LampPrototype ShallowClone();//浅拷贝
            public abstract LampPrototype DeepClone();//深拷贝
        }
    
        //灯的实现类
        [Serializable]
        public class Lamp : LampPrototype
        {
            //引用类型,电池
            public Battery battery = new Battery();
    
            public override int Use(){
                return battery.Capacity;
            }
    
            //浅拷贝
            public override LampPrototype ShallowClone(){
                return (Lamp)this.MemberwiseClone();
            }
            //深拷贝
            public override LampPrototype DeepClone(){
                MemoryStream stream = new MemoryStream();
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, this);
                stream.Position = 0;
                return (Lamp)formatter.Deserialize(stream);
            }
    
        }
    
        class Program
        {
            //设置原对象的数据
            public static void setOriginal(LampPrototype lampPro) {
                var lamp = lampPro as Lamp;
                lamp.battery.Capacity = 100;
            }
    
            //设置新对象的数据
            public static void setNew(LampPrototype lampPro) {
                var lamp = lampPro as Lamp;
                lamp.battery.Capacity = 80;
                Console.WriteLine("New Capacity::80");
            }
    
            static void Main(string[] args)
            {
                //原对象
                LampPrototype Originallamp = new Lamp();
                setOriginal(Originallamp);
    
                //浅拷贝
                Console.WriteLine();
                Console.WriteLine("After ShallowCopy,Original:");
                LampPrototype shallowAudio = Originallamp.ShallowClone();
                setNew(shallowAudio);//新对象使用电池,原对象的电池容量受到影响
                Console.WriteLine("Original Capacity:" + Originallamp.Use());
    
                //恢复原对象数据
                setOriginal(Originallamp);
    
                //深拷贝
                Console.WriteLine();
                Console.WriteLine("After DeepCopy,Original:");
                LampPrototype deepAudio = Originallamp.DeepClone();
                setNew(deepAudio);//新对象使用电池,原对象的电池容量没有受到影响
                Console.WriteLine("Original Capacity:" + Originallamp.Use());
    
                Console.ReadLine();
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
  • 相关阅读:
    Android Toast居中显示方法二
    为什么要改变this指向?
    【图像分类】基于深度学习的中草药分类系统的设计与实现(ResNet网络,附代码和数据集)
    数据结构——查找
    【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04
    模因币——在加密寒冬中逆流而上
    springboot集成dubbo+zookeeper简单搭建(细到你没有感觉)
    Python对Excel的读取
    28. 找出字符串中第一个匹配项的下标 KMP C++
    2310C++利用本来扩展模板类
  • 原文地址:https://blog.csdn.net/chen1083376511/article/details/134514127