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();
}
}