• Prototype 原型(创建型模式)


    依赖关系的倒置

    抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

    – 抽象A直接依赖于实现细节b

    image 

     

    –抽象A依赖于抽象B,实现细节b依赖于抽象B

    image

    动机(Motivation)

          在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
          如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象” ,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?

     

    意图(Intent)
    使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。——《设计模式》GoF

     

    结构(Structure)

    image

     

     

      实例代码

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;

    namespace testWpf
    {
        
    /// <summary>
        
    /// 抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
        
    /// </summary>
        [Serializable]
        
    public class NormalActor
        {
            
    //跟.Net的Clone不一样
            public virtual NormalActor Clone()
            {
                
    /*
                 * MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
                 * 如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;
                 * 因此,原始对象及其复本引用同一对象。
                 * 因此这里使用了对象序列化和反序列化的方式得到一个深拷贝对象
                 
    */
                MemoryStream stream 
    = new MemoryStream();
                BinaryFormatter formatter 
    = new BinaryFormatter(); 
                formatter.Serialize(stream, 
    this);
                stream.Position 
    = 0;
                
    return formatter.Deserialize(stream) as NormalActor;
            }
        }

        
    /// <summary>
        
    /// 抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
        
    /// </summary>
        [Serializable]
        
    public class FlyActor
        {
            
    //跟.Net的Clone不一样
            public virtual FlyActor Clone()
            {
                MemoryStream stream 
    = new MemoryStream();
                BinaryFormatter formatter 
    = new BinaryFormatter();
                formatter.Serialize(stream, 
    this);
                stream.Position 
    = 0;
                
    return formatter.Deserialize(stream) as FlyActor;
            }
        }

        
    /// <summary>
        
    /// 抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
        
    /// </summary>
        [Serializable]
        
    public class WaterActor
        {
            
    //跟.Net的Clone不一样
            public virtual WaterActor Clone()
            {
                MemoryStream stream 
    = new MemoryStream();
                BinaryFormatter formatter 
    = new BinaryFormatter();
                formatter.Serialize(stream, 
    this);
                stream.Position 
    = 0;
                
    return formatter.Deserialize(stream) as WaterActor;
            }
        }

        
    /// <summary>
        
    /// 虽然父类NormalActor已经是声明了可序列化标识“[Serializable]”,
        
    /// 但“[Serializable]”是不可继承的,所以子类如果要可以序列化,则还是要加上[Serializable]标识
        
    /// </summary>
        [Serializable]
        
    public class NormalActorA : NormalActor
        {
        }

        [Serializable]
        
    public class NormalActorB : NormalActor
        {
        }

        [Serializable]
        
    public class FlyActorA : FlyActor
        {
           
        }

        [Serializable]
        
    public class FlyActorB : FlyActor
        {
        }

        [Serializable]
        
    public class WaterActorA : WaterActor
        {
        }

        [Serializable]
        
    public class WaterActorB : WaterActor
        {
        }

        
    public class GameSystem
        {
            
    public NormalActor normalActor;
            
    public FlyActor flyActor;
            
    public WaterActor waterActor; 

            
    public void Run()
            {
                NormalActor normalActor1 
    = normalActor.Clone();
                NormalActor normalActor2 
    = normalActor.Clone();
                NormalActor normalActor3 
    = normalActor.Clone();
                NormalActor normalActor4 
    = normalActor.Clone();
                NormalActor normalActor5 
    = normalActor.Clone();

                FlyActor flyActor1 
    = flyActor.Clone();
                FlyActor flyActor2 
    = flyActor.Clone();

                WaterActor waterActor1 
    = waterActor.Clone();
                WaterActor waterActor2 
    = waterActor.Clone();
            }
        }

        
    public class App
        {
            
    public static void Main()
            {
                GameSystem gameSystem 
    = new GameSystem();
                gameSystem.normalActor 
    = new NormalActorA();
                gameSystem.flyActor 
    = new FlyActorB();
                gameSystem.waterActor 
    = new WaterActorA();
                gameSystem.Run();
            }
        }
    }

     

    Prototype模式的几个要点

    1. Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。
    2. Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone。
    3. Prototype模式中的Clone方法可以利用.NET中的Object类的MemberwiseClone()方法或者序列化来实现深拷贝。

     

    有关创建性模式的讨论

    1. Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的都是new所带来的耦合关系。
    2. Factory Method, Abstract Factory, Builder都需要一个额外的工厂类来负责实例化“易变对象”,而Prototype则是通过原型(一个特殊的工厂类)来克隆“易变对象”。
    3. 如果遇到“易变类”,起初的设计通常从FactoryMethod开始,当遇到更多的复杂变化时,再考虑重构为其他三种工厂模式( Abstract Factory,Builder , Prototype )。

    最后谈谈使用Prototype模式需要使用到的两个技术问题:MemberwiseClone与Clone,[Serializable]属性能否继承的问题

    一、MemberwiseClone与Clone

           MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

    下面的代码就是演示这个问题:

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;

    namespace testWpf
    {
        [Serializable]    
        
    class DemoClass    
        {        
            
    public int i = 0;
            
    public int[] iArr = { 123 };
            
    public DemoClass Clone1()        
            {            
                
    return this.MemberwiseClone() as DemoClass;        
            }        
            
            
    public DemoClass Clone2()        
            {           
                MemoryStream stream 
    = new MemoryStream();
                BinaryFormatter formatter 
    = new BinaryFormatter();
                formatter.Serialize(stream, 
    this);
                stream.Position 
    = 0;
                
    return formatter.Deserialize(stream) as DemoClass;
            }    
        }    
        
    class Program    
        {        
            
    static void Main(string[] args)
            {            
                DemoClass a 
    = new DemoClass();
                a.i 
    = 10;            
                a.iArr 
    = new int[] { 8910 };
                DemoClass b 
    = a.Clone1();            
                DemoClass c 
    = a.Clone2();            // 更改 a 对象的iArr[0], 导致 b 对象的iArr[0] 也发生了变化              
                a.iArr[0= 88;            
                Console.WriteLine(
    "MemberwiseClone");            
                Console.WriteLine(b.i);            
                
    foreach (var item in b.iArr)            
                {                
                    Console.WriteLine(item);            
                }            
                Console.WriteLine(
    "Clone2"); 
                Console.WriteLine(c.i);       
                
    foreach (var item in c.iArr)    
                {          
                    Console.WriteLine(item);
                }        
                Console.ReadLine();  
            }  
        }
    }

     二、[Serializable]属性能否继承的问题

    代码
        [Serializable]
        
    public abstract class CSMessage : MessageBase
        {
            
    private string userName;
            
    protected CSMessage(string anUserName)
            {
                userName 
    = anUserName;
            }

            
    public string UserName
            {
                
    get { return userName; }
            }

        }


        [Serializable]
        
    public class LoginMessage : CSMessage
        {
            
    private string password;
            
    public LoginMessage(string userName, string password)
                : 
    base(userName)
            {
                
    this.password = password;
            }
            
    public string Password
            {
                
    get { return password; }
            }
        }

    代码如上,测试发现类属性是不可以继承的,仔细推敲MSDN上关于对类属性是说明,类属性是一种标记当代码被编译为MSIL后由CLR根据类属性标记为其它附上相关的特性,唉。。不仔细看还是很容易弄错的

  • 相关阅读:
    拉普拉斯矩阵
    正定矩阵 和 半正定矩阵
    Random Walk
    论文解读(DGI)《DEEP GRAPH INFOMAX》
    python安装easyinstall/pip出错
    pip国内源设置
    在Jupyter Notebook添加代码自动补全功能
    [BUUCTF]PWN——bjdctf_2020_babystack2
    [BUUCTF]REVERSE——[BJDCTF 2nd]8086
    [BUUCTF]PWN——jarvisoj_tell_me_something
  • 原文地址:https://www.cnblogs.com/timy/p/1624169.html
Copyright © 2020-2023  润新知