c# 24种设计模式5原型模式(Prototype)

前言

原型模式其实C# Object中已经提供了一个Clone( )方法,平时很少用到,最近读Retrofit源码时候看到有这种使用方式。

定义

原型模式就是在系统clone()标记的基础上,对Clone()进行复写,不同的操作可以产生两种拷贝模式。

例子一场景 是个java的, 只是介绍使用的场景

UML类图

今天我们来讲原型模式,这个模式的简单程度是仅次于单例模式和迭代器模式,非常简单,但是要使 
用好这个模式还有很多注意事项。我们通过一个例子来解释一下什么是原型模式。 
现在电子账单越来越流行了,比如你的信用卡,到月初的时候银行就会发一份电子邮件到你邮箱中, 
说你这个月消费了多少,什么时候消费的,积分是多少等等,这个是每个月发一次,但是还有一种也是银 
行发的邮件你肯定有印象:广告信,现在各大银行的信用卡部门都在拉拢客户,电子邮件是一种廉价、快 
捷的通讯方式,你用纸质的广告信那个费用多高呀,比如我今天推出一个信用卡刷卡抽奖活动,通过电子 
账单系统可以一个晚上发送给 600 万客户,为什么要用电子账单系统呢?直接找个发垃圾邮件不就解决问 
题了吗?是个好主意,但是这个方案在金融行业是行不通的,银行发这种邮件是有要求的,一是一般银行 
都要求个性化服务,发过去的邮件上总有一些个人信息吧,比如“XX 先生”,“XX 女士”等等,二是邮件的 
到达率有一定的要求,由于大批量的发送邮件会被接收方邮件服务器误认是垃圾邮件,因此在邮件头要增 
加一些伪造数据,以规避被反垃圾邮件引擎误认为是垃圾邮件;从这两方面考虑广告信的发送也是电子账单系统(电子账单系统一般包括:账单分析、账单生成器、广告信管理、发送队列管理、发送机、退信处 
理、报表管理等)的一个子功能,我们今天就来考虑一下广告信这个模块是怎么开发的。那既然是广告信, 
肯定需要一个模版,然后再从数据库中把客户的信息一个一个的取出,放到模版中生成一份完整的邮件, 
然后扔给发送机进行发送处理,我们来看类图: 

例子1孙悟空的浅复制

///火影忍者中鸣人的影分身和孙悟空的的变都是原型模式
    class Client
    {
        static void Main(string[] args)
        {
            // 孙悟空 原型
            MonkeyKingPrototype prototypeMonkeyKing = new ConcretePrototype("MonkeyKing");

            // 变一个
            MonkeyKingPrototype cloneMonkeyKing = prototypeMonkeyKing.Clone() as ConcretePrototype;
            Console.WriteLine("Cloned1:\t"+cloneMonkeyKing.Id);

            // 变两个
            MonkeyKingPrototype cloneMonkeyKing2 = prototypeMonkeyKing.Clone() as ConcretePrototype;
            Console.WriteLine("Cloned2:\t" + cloneMonkeyKing2.Id);
            Console.ReadLine();
        }
    }

    /// <summary>
    /// 孙悟空原型
    /// </summary>
    public  abstract class MonkeyKingPrototype
    {
        public string Id { get; set; }
        public MonkeyKingPrototype(string id)
        {
            this.Id = id;
        }

        // 克隆方法,即孙大圣说“变”
        public abstract MonkeyKingPrototype Clone();
    }

    /// <summary>
    /// 创建具体原型
    /// </summary>
    public class ConcretePrototype : MonkeyKingPrototype
    {
        public ConcretePrototype(string id)
            : base(id)
        { }

        /// <summary>
        /// 浅拷贝
        /// </summary>
        /// <returns></returns>
        public override MonkeyKingPrototype Clone()
        {
            // 调用MemberwiseClone方法实现的是浅拷贝,另外还有深拷贝
            return (MonkeyKingPrototype)this.MemberwiseClone();
        }
    }

上面原型模式的运行结果为(从运行结果可以看出,创建的两个拷贝对象的ID属性都是与原型对象ID属性一样的):

上面代码实现的浅拷贝的方式,浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么这两个对象将引用同一个字符串,而深拷贝是对对象实例中字段引用的对象也进行拷贝,如果一个对象有一个指向字符串的字段,并且我们对该对象进行了深拷贝的话,那么我们将创建一个对象和一个新的字符串,新的对象将引用新的字符串。也就是说,执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响,而执行浅拷贝创建的新对象与原来对象共享成员,改变一个对象,另外一个对象的成员也会改变。

介绍完原型模式的实现代码之后,下面看下原型模式的类图,通过类图来理清原型模式实现中类之间的关系。具体类图如下:

三、原型模式的优缺点

原型模式的优点有:

  1. 原型模式向客户隐藏了创建新实例的复杂性
  2. 原型模式允许动态增加或较少产品类。
  3. 原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
  4. 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构

原型模式的缺点有:

  1. 每个类必须配备一个克隆方法
  2. 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

四、.NET中原型模式的实现

在.NET中可以很容易地通过实现ICloneable接口(这个接口就是原型,提供克隆方法,相当于与上面代码中MonkeyKingPrototype抽象类)中Clone()方法来实现原型模式,如果我们想我们自定义的类具有克隆的功能,首先定义类继承与ICloneable接口并实现Clone方法。在.NET中实现了原型模式的类如下图所示(图中只截取了部分,可以用Reflector反编译工具进行查看):

例子2 孙悟空的深复制

分析:

孙悟空:根据自己的形状复制(克隆)出多个身外身

软件开发:通过复制一个原型对象得到多个与原型对象一模一样的新对象

工作原理:将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程

创建新对象(也称为克隆对象)的工厂就是原型类自身,工厂方由负责复制原型对象的克隆方法来实现

通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每一个克隆对象都是独立

通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象

原型模式的结构

原型模式包含以下3个角色:

?Prototype(抽象原型类)

?ConcretePrototype(具体原型类)

?Client(客户类)

浅克隆与深克隆

浅克隆(Shallow Clone)当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制

深克隆(Deep Clone)除了对象本身被复制外,对象所包含的所有成员变量也将被复制

[Serializable]  //深克隆时需要将类标记为Serializable
public class Person:ICloneable
{
    public string CurrentEmployee { get; set; }
    public Member Member { get; set; }
    public Person()
    {
        this.CurrentEmployee = "admin";
        Member member = new Member();
        member.Id = 3;
        member.Name = "Mem";
        this.Member = member;
    }
    public object Clone()
    {
        return this.MemberwiseClone();
    }
    #region 静态方式创建对象
    private static Person _person;
    /// <summary>
    /// 静态构造函数,永远只运行一次
    /// </summary>
    static Person()
    {
        _person = new Person();
    }
    public static Person StaticClone()
    {
        return _person.MemberwiseClone() as Person;
    }
    #endregion
}
[Serializable]
public class Member
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public class SerializeHelper
{
    /// <summary>
    /// 序列化
    /// </summary>
    /// <param name="target"></param>
    /// <returns></returns>
    public static string Serializable(object target)
    {
        using(MemoryStream stream=new MemoryStream())
        {
            new BinaryFormatter().Serialize(stream,target);
            return Convert.ToBase64String(stream.ToArray());
        }
    }
    /// <summary>
    /// 反序列化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="target"></param>
    /// <returns></returns>
    public static T Derializable<T>(string target)
    {
        byte[] targetArray = Convert.FromBase64String(target);
        using (MemoryStream stream = new MemoryStream(targetArray))
        {
            return (T)(new BinaryFormatter().Deserialize(stream));
        }
    }
    /// <summary>
    /// 合并反序列化与序列化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t"></param>
    /// <returns></returns>
    public static T DeepClone<T>(T t)
    {
        return Derializable<T>(Serializable(t));
    }
}
//浅表克隆,原来创建的对象值会改变
Person p = new Person();
Person p1 = p.Clone() as Person;
p1.CurrentEmployee = "user";
p1.Member.Id = 1;
p1.Member.Name = "pp1";
//深度克隆,原来创建的对象值不会改变
Person p2 = p.Clone() as Person;
Person p3 = SerializeHelper.Derializable<Person>(SerializeHelper.Serializable(p2));
//或者简写
//Person p3 = SerializeHelper.DeepClone<Person>(p2);
p3.Member.Id = 6;
p3.Member.Name = "dd3";
Console.Read();

例子3:原型模式应用

  首先从实际生活来了解原型模式的由来,假设你有一份非常好的讲义,你的朋友也想要一份,那么怎么办?重新手抄一份?显然不是,当然是用复印机复印一份来得方便、直接,并且准确性也高,这种用原型来复制而不是重新创建的思维方式就是原型模式的核心思想。

  Prototype Pattern也是一种创建型模式,它关注的是大量相同或相似对象的创建问题。应用原型模式就是建立一个原型,然后通过对原型来进行复制的方法,来产生一个和原型相同或相似的新对象,或者说用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

 原型模式参与者:

  ? Prototype:原型类,声明一个Clone自身的接口;

  ? ConcretePrototype:具体原型类,实现一个Clone自身的操作。

  在原型模式中,Prototype通常提供一个包含Clone方法的接口,具体的原型ConcretePrototype使用Clone方法完成对象的创建。

/// <summary>
    /// The ‘Prototype‘ abstract class
    /// </summary>
    public abstract class Prototype
    {
        private string _id;
        /// <summary>
        /// Constructor
        /// </summary>
        public Prototype(string id)
        {
            this._id = id;
        }
        /// <summary>
        /// Gets id
        /// </summary>
        public string Id
        {
            get { return _id; }
        }
        public abstract Prototype Clone();
    }

ConcretePrototype1.cs

 public class ConcretePrototype1 : Prototype
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ConcretePrototype1(string id)
            : base(id)
        {
        }

        /// <summary>
        /// Returns a shallow copy
        /// </summary>
        /// <returns></returns>
        public override Prototype Clone()
        {
            return (Prototype)this.MemberwiseClone();
        }
    }

ConcretePrototype2.cs

 public class ConcretePrototype2 : Prototype
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ConcretePrototype2(string id)
            : base(id)
        {
        }

        /// <summary>
        /// Returns a shallow copy
        /// </summary>
        /// <returns></returns>
        public override Prototype Clone()
        {
            return (Prototype)this.MemberwiseClone();
        }
    }

Client.cs

   static void Main(string[] args)
        {
            // Create two instances and clone each
            ConcretePrototype1 p1 = new ConcretePrototype1("I");
            ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
            Console.WriteLine("Cloned: {0}", c1.Id);

            ConcretePrototype2 p2 = new ConcretePrototype2("II");
            ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
            Console.WriteLine("Cloned: {0}", c2.Id);
        }
Cloned: I
Cloned: II
请按任意键继续. .

原型模式的实践

ColorPrototype.cs

  /// <summary>
    /// The ‘Prototype‘ abstract class
    /// </summary>
    public abstract class ColorPrototype
    {
        public abstract ColorPrototype Clone();
    }

Color.cs

 /// <summary>
    /// The ‘ConcretePrototype‘ class
    /// </summary>
    public class Color : ColorPrototype
    {
        private int _red;
        private int _green;
        private int _blue;

        /// <summary>
        /// Constructor
        /// </summary>
        public Color(int red, int green, int blue)
        {
            this._red = red;
            this._green = green;
            this._blue = blue;
        }

        /// <summary>
        /// Create a shallow copy
        /// </summary>
        public override ColorPrototype Clone()
        {
            Console.WriteLine("Cloning color RGB: {0,3},{1,3},{2,3}", _red, _green, _blue);
            return this.MemberwiseClone() as ColorPrototype;
        }
    }

ColorManager.cs

  /// <summary>
    /// Prototype manager
    /// </summary>
    public class ColorManager
    {
        private Dictionary<string, ColorPrototype> _colors = new Dictionary<string, ColorPrototype>();

        /// <summary>
        /// Indexer
        /// </summary>
        public ColorPrototype this[string key]
        {
            get { return _colors[key]; }
            set { _colors.Add(key, value); }
        }
    }

Client.cs

  static void Main(string[] args)
        {
            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;
        }

输出

Cloning color RGB: 255,  0,  0
Cloning color RGB: 128,211,128
Cloning color RGB: 211, 34, 20
请按任意键继续. . .

5、原型模式应用分析

  原型模式可以适用于以下情形:

  ? 当一个系统应该独立于它的产品创建、构成和表示时;

  ? 当要实例化的类是在运行时刻指定时,例如通过动态装载来创建一个类;

  ? 为了避免创建一个与产品类层次平行的工厂类层次时;

  ? 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并Clone它们可能比每次用合适的状态手工实例化该类更方便一些。

  原型模式具有以下特点:

  ? 对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目;

  ? 允许客户只通过注册原型实例就可以将一个具体产品类并入到系统中,客户可以在运行时刻建立和删除原型;

  ? 减少了子类的构造。原型模式是Clone一个原型而不是请求工厂方法创建一个,所以它不需要一个与具体产品类平行的Creator类层次;

  ? 原型模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响旧系统;

  ? 产品类不需要非得有任何事先确定的等级结构,因为原型模式适用于任何的等级结构;

  ? 原型模式的最重要缺点就是每一个类必须配备一个Clone方法,而且这个Clone方法需要对类的功能进行通盘考虑。这对全新的类来说不是很难,但对已有的类进行改造时,不一定是容易的事。

本文资料来自互联网整理,为方便大家更多的了解设计模式,若有侵权等本文整理尽快下架.

原文地址:https://www.cnblogs.com/zuochanzi/p/8900507.html

时间: 2024-10-09 08:15:56

c# 24种设计模式5原型模式(Prototype)的相关文章

二十四种设计模式:原型模式(Prototype Pattern)

原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. 示例有一个Message实体类,现在要克隆它. MessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Prototype { /// <summary> /// Message实体类 /// </summary> publi

23种设计模式之原型模式(Prototype)

在系统开发过程中,有时候有些对象需要被频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后通过复制这个原型对象的办法,创建出更多同类型的对象.原型模式是一种对象创建型模式,用原型实例制定创建对象的种类,并且通过复制这些原型创建新的对象.原型模式又可分为两种:浅克隆和深克隆.浅克隆仅仅复制所考虑的对象,而不复制它所引用的对象,也就是其中的成员对象并不复制:深克隆除了对象本身被复制外,对象包含的引用也被复制,即成员对象也被复制. 优点: 1)可以在运行时添加或删除产品. 2)通过改

【Unity与23种设计模式】原型模式(Prototype)

GoF中定义: "使用原型对象来产生指定类的对象,所以产生对象时,是使用复制原型对象来完成." Unity中 开发者可以组装游戏对象 它可以包括复杂的组件 组装好了之后,就可以将其存储为Prefab类型的Unity Asset资源 程序代码中使用的实例化方法(GameObject.Instance) 就是一种原型模式的应用. 原型模式原意为: 将一个复杂对象的组合方式先行设置好 后续使用时就不必再经过相同的组装流程 只需要从做好的"原型"完整地复制出来就可以了.

【设计模式】—— 原型模式Prototype

前言:[模式总览]——————————by xingoo 模式意图 由于有些时候,需要在运行时指定对象时哪个类的实例,此时用工厂模式就有些力不从心了.通过原型模式就可以通过拷贝函数clone一个原有的对象,给现在的对象使用,从而创建更多的同类型的对象. 模式结构 [简单原型模式]用于原型的版本不多的时候 [登记模式的原型模式]如果原型的实现很多种版本,那么通过一个登记管理类,可以方便的实现原型的管理. Prototype 原型接口,定义原型的结构. ConcretePrototype 原型的具体

设计模式 笔记 原型模式 prototype

//---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2:动机: 3:适用性: 1>当一个系统应该独立于它的产品创建.构成和表示时 2>当要实例化的类是在运行时刻制定时,例如通过动态装载 3>为了避免创建一个与产品类层次平行的工厂类层次时 4>当一个类的实例只能有几个不同状

创建型设计模式之原型模式(Prototype)

结构   意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性 当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或者 当一个类的实例只能有几个不同状态组合中的一种时.建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些. 1 using System; 2 3 // Objects which are to work as prototypes must be based on class

Java设计模式四: 原型模式(Prototype Pattern)

网上找了好多这个模型的资料说的都不透彻,看了半天都是云里雾里.只好自己操刀研究一把. 原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据. 原型模式中的拷贝分为"浅拷贝"和"深拷贝":浅拷贝: 对值类型的成员变量进行值的复制,对引用类型

设计模式之原型模式prototype

1.原型模式的使用和本质.以及优势: a.通过 new 产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式. b.原型模式的使用就是 java 中的克隆技术,以某个对象为原型,复制出新的对象.显然,新的对象具备原型对象的特点. c.其优势有:效率高(直接克隆,避免了重新执行构造过程步骤). d.克隆类似于 new, 但是不同于 new .new 创建新的对象属性采用的是默认值.克隆出的对象的属性值完全和原型对象相同.并且克隆出来的新对象改变不会影响原型对象.(可以对克隆对象修改属

23种设计模式(4) - 原型模式

1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.UML图 3.组成 原型类:用来作拷贝的类,实现了Cloneable类,并重写了 clone方法.重写Cloneable方法才能使用clone方法,否则会报CloneNotSupportedException的异常:重写clone方法是因为该方法原来是protected类型的,不重写不能调用该方法. 4.代码 // 原型类 public class Prototype implements Cloneable { p