1. 什么是原型模式?

如果对象的创建成本过大,而同一个类的不同对象之间差别不大(大部分字段都相同),就可以利用对已有对象(原型)进行复制的方式,来创建新的对象,以达到节省创建时间的目的,这种基于原型来创建对象的方式叫做原型设计模式,简称原型模式

2. 原型模式的两种实现方式

原型模式有两种实现方式,深拷贝喝浅拷贝。浅拷贝只会复制对象中基本数据类型喝引用对象的内存地址,不会递归的复制引用对象,以及引用对象的引用对象。。。而深拷贝得到的是一份份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间

如果要拷贝的对象是不可变对象,浅拷贝共享不可变对象是没问题,但对于可变对象来说,浅拷贝得到的对象和原始对象会共享部分数据,就有可能出现数据被修改的风险,也就变的复杂多了。所以 没有充分的理由,不要为了一点点的性能而使用浅拷贝。

代码举例

示例场景:图形编辑器中的形状复制

假设我们有一个图形编辑器,用户可以创建和复制各种形状。我们将使用原型模式来实现形状的复制功能。

首先定义原型接口
public interface IShape : ICloneable
{
    string Type { get; }
    string Color { get; set; }
    int X { get; set; }
    int Y { get; set; }
    void Draw();
    IShape Clone();
}
实现具体原型类
public class Circle : IShape
{
    public string Type => "Circle";
    public string Color { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Radius { get; set; }

    public Circle(string color, int x, int y, int radius)
    {
        Color = color;
        X = x;
        Y = y;
        Radius = radius;
    }

    public void Draw()
    {
        Console.WriteLine($"Drawing a {Color} circle at ({X},{Y}) with radius {Radius}");
    }

    public IShape Clone()
    {
        // 使用MemberwiseClone实现浅拷贝
        return (IShape)this.MemberwiseClone();
    }

    object ICloneable.Clone()
    {
        return Clone();
    }
}

public class Rectangle : IShape
{
    public string Type => "Rectangle";
    public string Color { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }

    public Rectangle(string color, int x, int y, int width, int height)
    {
        Color = color;
        X = x;
        Y = y;
        Width = width;
        Height = height;
    }

    public void Draw()
    {
        Console.WriteLine($"Drawing a {Color} rectangle at ({X},{Y}) with width {Width} and height {Height}");
    }

    public IShape Clone()
    {
        // 使用MemberwiseClone实现浅拷贝
        return (IShape)this.MemberwiseClone();
    }

    object ICloneable.Clone()
    {
        return Clone();
    }
}
实现原型管理器(可选
public class ShapeCache
{
    private static Dictionary<string, IShape> shapeMap = new Dictionary<string, IShape>();

    public static IShape GetShape(string shapeId)
    {
        IShape cachedShape = shapeMap[shapeId];
        return cachedShape.Clone();
    }

    public static void LoadCache()
    {
        Circle circle = new Circle("Red", 10, 10, 20);
        shapeMap.Add("1", circle);

        Rectangle rectangle = new Rectangle("Blue", 20, 20, 30, 40);
        shapeMap.Add("2", rectangle);
    }
}

使用示例
class Program
{
    static void Main(string[] args)
    {
        // 1. 直接克隆示例
        Circle originalCircle = new Circle("Green", 5, 5, 15);
        Console.WriteLine("Original Circle:");
        originalCircle.Draw();

        IShape clonedCircle = originalCircle.Clone();
        Console.WriteLine("Cloned Circle:");
        clonedCircle.Draw();

        // 修改克隆后的对象不会影响原对象
        clonedCircle.Color = "Yellow";
        clonedCircle.X = 15;
        Console.WriteLine("After modifying cloned circle:");
        Console.WriteLine("Original Circle:");
        originalCircle.Draw();
        Console.WriteLine("Cloned Circle:");
        clonedCircle.Draw();

        Console.WriteLine("\n--------------------------------\n");

        // 2. 使用原型管理器示例
        ShapeCache.LoadCache();

        IShape clonedShape1 = ShapeCache.GetShape("1");
        Console.WriteLine("Shape 1:");
        clonedShape1.Draw();

        IShape clonedShape2 = ShapeCache.GetShape("2");
        Console.WriteLine("Shape 2:");
        clonedShape2.Draw();

        // 修改从缓存中获取的克隆对象
        clonedShape1.Color = "Purple";
        Console.WriteLine("Modified cloned Shape 1:");
        clonedShape1.Draw();

        // 再次从缓存获取相同的形状,确认原缓存对象未被修改
        IShape clonedShape1Again = ShapeCache.GetShape("1");
        Console.WriteLine("Shape 1 from cache again:");
        clonedShape1Again.Draw();
    }
}