原型模式
发布日期:2021-05-20 00:21:59 浏览次数:25 分类:精选文章

本文共 3398 字,大约阅读时间需要 11 分钟。

原型模式(Prototype Pattern)是一种软件设计模式,通过使用原型实例来指定创建对象的种类,并通过拷贝这些原型创建新的对象,从而避免重复代码的冗余。这一模式在开发中广泛应用,尤其在需要灵活对象创建的情况下。

什么是原型模式?

原型模式的核心思想是定义一个接口(通常称为原型接口),然后通过复制现有的实例并根据需要进行修改来创建新的实例。这使得系统能够在运行时灵活配置和创建对象,而无需公开构造函数或手动进行复杂的初始化操作。

为什么要使用原型模式?

在面对新对象的创建需求时,直接使用 new 运算符可能导致代码冗余,难以管理对象的创建逻辑。而原型模式通过复制现有对象实例来创建新对象,既提高了效率,又简化了代码结构。

原型模式的适用场景

原型模式适用于以下场景:

  • 当系统需要独立于具体对象的构造过程管理时。
  • 当需要在运行时客户端动态决定对象的具体实现方式时。
  • 当需要避免在类层次中引入工厂类来管理对象的创建时。
  • 当对象的状态在多个可能组合中时,通过预先定义原型来优化性能。

原型模式的优缺点

优点:

  • 提供与构造函数 decoupling 的性能优势。
  • 适用于大量对象的创建,其复杂性较低。

缺点:

  • 必须实现 Cloneable 接口,增加了程序的复杂度。
  • 当对象需要深度复制时,实现起来相对繁琐。

原型模式的分类

原型模式可以根据对象的复制方式划分为两种类型:

  • 值类型的原型模式:采用 MemberwiseClone 方法实现浅复制,适用于对象内部所有成员变量都为值类型的情况。
  • 引用类型的原型模式:需要自定义克隆方法实现深复制,确保新对象复制所有引用成员变量的引用。例如,使用 C# 的 Object.MemberwiseClone 方法实现浅复制,或者自定义克隆逻辑进行深复制。

具体案例:水果布丁制作

在实际开发中,原型模式可以用于创建对象的多种状态。例如,制作水果布丁时,不同的口味可能需要不同的材料组合。通过使用原型模式,可以预先定义各种原型,并通过复制这些原型来创建新的布丁实例。

值类型的原型模式示例

假设我们有一个 Pudding 类,它实现了 ICloneable 接口:

class Pudding : ICloneable
{
private string name; // 水果布丁的名字
private int milk; // 牛奶
private int egg; // 鸡蛋
private int unsaltedbutter; // 淡奶油
private int sugar; // 糖
private string fruit; // 水果
public Pudding(string name)
{
this.name = name;
}
public void SetBasicMaterials(int milk, int egg, int unsaltedbutter)
{
this.milk = milk;
this.egg = egg;
this.unsaltedbutter = unsaltedbutter;
}
public void SetFlavorMaterials(int sugar, string fruit)
{
this.sugar = sugar;
this.fruit = fruit;
}
public object Clone()
{
return (object)this.MemberwiseClone();
}
}

在客户端代码中:

Pudding p1 = new Pudding("香蕉布丁");
p1.SetBasicMaterials(250, 2, 60);
p1.SetFlavorMaterials(30, "香蕉丁");
Pudding p2 = (Pudding)p1.Clone();
p2.SetFlavorMaterials(40, "香蕉丁");
Pudding p3 = (Pudding)p1.Clone();
p3.SetFlavorMaterials(45, "香蕉丁加苹果丁");
p1.Show();
p2.Show();
p3.Show();
Console.ReadKey();

这样,原始对象 p1 不会受到 p2p3 修改的影响,每个对象都有正确的独立状态。

引用类型的原型模式示例

在引用类型的示例中,我们可以看到更复杂的对象结构。例如,Flavormaterials 类作为一个独立的对象,采用引用类型的原型模式,通过复制实现深复制:

public class Flavormaterials : ICloneable
{
private int sugar;
private string fruit;
public int Sugar
{
get { return sugar; }
set { sugar = value; }
}
public string Fruit
{
get { return fruit; }
set { fruit = value; }
}
public object Clone()
{
return (object)MemberwiseClone();
}
}

Pudding 类中:

class Pudding : ICloneable
{
private string name;
private int milk;
private int egg;
private int unsaltedbutter;
private Flavormaterials _flavorMaterial = new Flavormaterials();
public Pudding(string name)
{
this.name = name;
}
public void SetFlavorMaterials(int sugar, string fruit)
{
_flavorMaterial.Sugar = sugar;
_flavorMaterial.Fruit = fruit;
}
public object Clone()
{
Pudding copy = new Pudding(this.name);
copy.milk = this.milk;
copy.egg = this.egg;
copy.unsaltedbutter = this.unsaltedbutter;
return copy;
}
}

在客户端代码中:

Pudding p1 = new Pudding("香蕉布丁");
p1.SetBasicMaterials(250, 2, 60);
p1.SetFlavorMaterials(30, "香蕉丁");
Pudding p2 = (Pudding)p1.Clone();
p2.SetFlavorMaterials(40, "香蕉丁");
Pudding p3 = (Pudding)p1.Clone();
p3.SetFlavorMaterials(45, "香蕉丁加苹果丁");
p1.Show();
p2.Show();
p3.Show();
Console.ReadKey();

这里,p2p3 分别复制了 p1 的基本属性和口味属性,显示的结果也说明了深复制的优势。

上一篇:适配器模式
下一篇:建造者模式

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年04月30日 22时20分43秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章