原型模式

摘自《大话设计模式》(程杰 著)
原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。

每 NEW 一次,都需要执行一次构造函数,
如果构造函数的执行时间很长,那么多次的执行这个初始化操作就实在是太低效了。
一般在初始化的信息不发生变化的情况下,克隆是最好的办法。
这既隐藏了对象创建的细节,又对性能是大大的提高

image

代码结构

Prototype.cs 原型类

abstract class Prototype
{
    private string id;

    public Prototype(string id)
    {
        this.id = id;
    }

    public string Id
    {
        get { return id; }
    }

    // 关键
    public abstract Prototype Clone();
}

ConcretePrototype.cs 具体原型类

class ConcretePrototype : Prototype
{
    public ConcretePrototype(string id) : base(id)
    {

    }

    // 创建当前对象的浅表副本
    /*
     * 方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
     * 如果字段是值类型的,则对该字段执行逐位复制。
     * 如果字段是引用类型,则复制引用但不复制引用的对象。
     * 因此,原始对象及其副本引用同一对象。
     */
    public override Prototype Clone()
    {
        return (Prototype)this.MemberwiseClone();
    }
}

Program.cs 客户端代码

ConcretePrototype p1 = new ConcretePrototype("I");

// 克隆类 ConcretePrototype 的对象 p1 就能得到新的实例 c1
ConcretePrototype c1 = (ConcretePrototype)p1.Clone();
Console.WriteLine("Cloned: {0}", c1.Id);

Console.Read();

但对于.NET而言,那个原型抽象类Prototype是用不着的,因为克隆实在是太常用了,
所以.NET在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),
实际上只需要实现这个接口就可以完成原型模式了。

浅复制/深复制

浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深复制要深入到多少层,需要事先就考虑好,而且要当心出现循环引用的问题。

示例

WorkExperience.cs 工作经历类

//工作经历
class WorkExperience: ICloneable
{
    private string workDate;
    public string WorkDate
    {
        get { return workDate; }
        set { workDate = value; }
    }

    private string company;
    public string Company
    {
        get { return company; }
        set { company = value; }
    }

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

}

Resume.cs 简历类

class Resume: ICloneable
{
    private string name;
    private string sex;
    private string age;
    private WorkExperience work;

    public Resume(string name)
    {
        this.name = name;
        work = new WorkExperience();
    }

    private Resume(WorkExperience work)
    {
        this.work = (WorkExperience)work.Clone();
    }

    // 设置个人信息
    public void SetPersonalInfo(string sex, string age)
    {
        this.sex = sex;
        this.age = age;
    }

    // 设置工作经历
    public void SetWorkExperience(string workDate, string company)
    {
        work.WorkDate = workDate;
        work.Company = company;
    }

    // 显示
    public void Display()
    {
        Console.WriteLine("{0}{1}{2}", name, sex, age);
        Console.WriteLine("工作经历: {0} {1}", work.WorkDate, work.Company);
    }

    public Object Clone()
    {
        // 调用私有的构造方法,让"工作经历"克隆完成
        // 然后再给这个"简历"对象的相关字段赋值
        // 最终返回一个深复制的简历对象
        Resume obj = new Resume(this.work);
        obj.name = this.name;
        obj.sex = this.sex;
        obj.age = this.age;
        return obj;
    }
}

Program.cs 客户端

Resume a = new Resume("小明");
a.SetPersonalInfo("男", "24");
a.SetWorkExperience("1998-2000", "XX公司");

Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "YY企业");

Resume c = (Resume)a.Clone();
c.SetWorkExperience("1998-2003", "ZZ企业");

a.Display();
b.Display();
c.Display();

Console.Read();
posted @ 2025-12-17 10:07  苦涩如影相随固  阅读(65)  评论(0)    收藏  举报