【设计模式】原型模式(Prototype)

原型(Prototype)模式的用意是:通过给出一个原型对象来指明索要创建的对象类型,然后用复制这个原型对象的方法创建出更多的同类型对象。

不同语言对原型模式的支持

一、Java
Java语言中已经提供了clone方法,定义在Object类中,需要实现克隆功能的类,只需要实现java.lang.Cloneable接口即可。

二、C#

  • 在C#里面,我们可以很容易的通过Clone()方法实现原型模式。任何类,只要想支持克隆,必须实现C#中的ICloneable接口。
    ICloneable接口中有一Clone方法,可以在类中腹泻,实现自定义的克隆方法。
  • 克隆的实现方法有两种:浅复制(shallow copy)和深复制(deep copy)
  • 浅复制:只负责克隆按值传递的数据(比如基本数据类型和String类型)
  • 深复制:除了浅复制要克隆的值外,还负责引用雷子那个(属性的类型也是对象)的数据。
  • 需要注意的是:执行拷贝后,原来的对象和新创建的对象不会共享任何东子,改变一个对象和另一个对象没有任何影响。

Prototype模式的结构

在这里插入图片描述

  • 客户角色(Client)角色:
    客户类提出创建对象的请求。
  • 抽象原型(Prototype)角色
    这是一个抽象角色,通常由一个C#接口或抽象类实现,此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色同创实现了ICloneable接口。
  • 具体原型(Concrete Prototype)角色
    被复制的对象。此角色需要实现抽象原型角色索要求的接口。

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

优点

  • 想要改某份简历,只需要对这一份简历作一定的修改就可以,不会影响到其他简历,相同的部分就不用再重复。
  • 一般在初始化的信息不发生变化的情况下,克隆是最好的方法,即隐藏了创建的细节,又对性能是大大的提高。

复制

  • 浅复制:被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 深复制:吧引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

Prototype模型本质

  • 克隆生成对象
  • 如果要生成一大批很相像的类的实例时,不用每次去做重复的复制工作。
    eg:如果有一个类A,打算生成100个A的实例,并且这些实例的变量值大部分相同,只有一小部分不一样。使用原型只需要生成一个A的实例,在通过clone来生成其他的实例,然后一一修改其他实例不同的地方。

Prototype模型与Factory模式的关系

原型模式使用起来完全可以达到工厂模式的效果;而且用起来甚至比工厂模式更方便、灵活。
对于工厂模式与原型模式在功能上的这点巧合,也许是因为本来工厂模式和原型模式都是创建型模式(三种类型,行为,结构)。他们的基本功能都能生成对象,因为是的原型模式在功能上可以替代工厂模式。

Prototype模式如何实现Factory模式的功能

  • 工厂模式实现的生产产品的功能,关键是利用了继承的特性。也就是说,你生成的产品,一定是由同一个抽象产品类派生出来的。所以,在工厂模式下,你如果要生成一类产品,就要引入一个抽像产品类,然后再由它派生出具体产品。
  • 同样,在原型模式中,你完全可以同样定义一个这样的“抽象产品——具体产品”层次,再利用具体产品本身的clone功能来产生具体产品本身。从而达到实现工厂模式功能的目的。
  • 实际上,在原型模式中,每个具体产品就扮演了工厂模式里的具体工厂的角色(因为每个具体产品都具有生成自己拷贝的功能,从这种意义上讲,这正是工厂的作用)

总结

  • Prototype模式通过复制原型(Prototype)而获得新对象创建的功能,这里Prototype本身就是“对象工厂”(因为能够生产对象)
  • Prototype模式从自身复制自己创建新对象

一、优点

  • Prototype模式允许动态增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此增加新产品对整个结构没有影响。
  • Prototype模式提供了简化的创建结构。工厂方法模式常常需要有一个与产品类等级结构相同的等级结构,而Prototype模式就不需要这样

二、缺点
Prototype模式的最主要的缺点就是每个原型的子类都必须实现clone的操作,尤其在包含引用类型饿随想时,clone方法会比较麻烦,必须要能够递归地让所有的相关对象都要正确地实现克隆。

实例

【问题】订单处理系统
现在有个个订单处理系统,里面有一个保存订单的业务功能,需我:每当订单的预定产品数量超过1000的时候,就需要把订单拆成两份订单来保存。如果拆成两份后还是超过1000,则继续拆分,直到每份产品预订数量不超过1000.
根据业务,目前的订单系统分成两种,一种是个人订单、一种是公司订单。
客户名称、产品对象(ID, Name),订购产品数量。
公司名称、产品对象(ID, Name),订购产品数量。

【代码】

using System;

namespace OrderPrototype
{
    class Product
    {
        private string ID, name;

        public Product() { }
        public Product(string ID,string  name)
        {
            this.ID = ID;
            this.name = name;
        }

        public string id
        {
            get { return ID; }
            set { ID = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }

    abstract class Iorder
    {
        abstract public Iorder Clone();
    }

    class Order:Iorder
    {
        private string name;
        private int num;
        private Product pro;

        public Order(string name)
        {
            this.name = name;
            this.pro = new Product();
        }
        public int Num
        {
            get { return num; }
            set { num = value; }
        }
        private Order(Product pro)
        {
            this.pro=(Product)pro.Clone();
        }

        public void setProduct(string name,string ID)
        {
            pro.Name = name;
            pro.id = ID;
        }

        public override Iorder Clone()
        {
            Order obj = new Order(this.pro);
            obj.name = this.name;
            obj.num = this.num;
            return obj;
        }

        public void Display()
        {
            Console.WriteLine("订单持有人/公司:"+name+"  订单数量:"+num);
            Console.WriteLine("订单编号:" + pro.id + "  订单产品:" + pro.Name);
        }
    }

    class Client
    {
        static void Main(string[] args)
        {
            Order person = new Order("小菜");
            person.Num=12300;
            person.setProduct("《设计模式》", "123456789");
            Order []orders=new Order[10010];
            int n = person.Num / 1000;
            if (person.Num>1000)
            {
                for (int i=1 ; i<=n ; i++)
                {
                    orders[i] = (Order)person.Clone();
                    orders[i].Num = 1000;
                }
                if (person.Num % 1000 != 0)
                {
                    orders[n + 1] = (Order)person.Clone();
                    orders[n + 1].Num = person.Num % 1000;
                    n++;
                }
            }
            for(int i=1;i<=n;i++)
            {
                orders[i].Display();
            }
        }
    }
}

【UMLt图】
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值