复制对象有哪些好的设计模式?

时间:2009-09-06 19:15:44

标签: design-patterns

我需要复制一个具有相当深的成员变量层次结构的对象(即,该对象具有多个不同类型的成员,每个成员具有多个不同类型的成员,等等)。执行深层复制需要在许多类中实现clone()方法,这对我的应用程序来说似乎有点过分了。

我提出的解决方案相当简单,但我想知道这是不是一个坏主意。我的解决方案如下:

  • 定义一个空接口Settings
  • 定义名为IsCopyable的界面,该界面包含方法getSettings()applySettings(Settings s)
  • 对于实现X的给定类IsCopyable,将编写一个实现接口Settings的类,其中包含必须应用于类{{}对象的“设置”。 1}}以便复制它。 (我通常在课程X中嵌套这个课程,所以我有X,但这可以在其他地方完成。)

然后,复制类X的实例:

X.Settings implements Settings

即,要复制给定对象,请创建该对象的新实例,然后在要复制的对象上调用X myX = new X(); // Stuff happens to myX. // Now we want to copy myX. X copyOfX = new X(); copyOfX.applySettings(myX.getSettings()); ,将生成的getSettings()对象作为值传递给{{1}在新实例上。 (当然,复制可以包含在名为copy()或其他东西的成员中。)

这对我的特定问题非常有效,但我做的事情是愚蠢的吗?我(很差)重新发明了已经存在的东西吗?

提前致谢。

克里斯

5 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

这可能是代码味道,您可能需要采取另一种方法。 您的对象应该“显然是可复制的”,有几种方法可以创建这种类型的对象:

  • 您的对象是值对象(struct 在C#)中,仅参考其他人 值对象或不可变对象。 (在这种情况下,克隆就像影响变量一样容易)
  • 你的对象是不可变的,所以你 不需要克隆它,只能共享引用。
  • 你的物品是一袋“物业” 这很容易克隆,因为每个 成员也很明显 可复制的。 (WCF中的绑定是这样的)
  • 您的对象只是一个可序列化的数据,因此您可以对其进行序列化并反序列化以创建新实例。

我不太了解你的设计是否告诉你它是否是最好的解决方案,但一般我所做的是创建一个工厂,这只是一个“包属性”来创建我的对象,然后我实现ICloneable在工厂。

答案 2 :(得分:0)

答案 3 :(得分:0)

我目前遇到类似情况,我必须复制asp.net的客户服务器控件。问题在于,由于复杂的控制层次结构,使用MemberwiseClone()进行克隆会产生一些不良影响。

我还不知道如何解决这个问题,但我有一些想法是实现ICloneable接口,但没有使用MemberwiseClone()而是创建一个新的实例,如

public class MyObject : ICloneable
{
   ...

   public object ICloneable.Clone()
   {
      MyObject clone = new MyObject();
      //copy everything I want to have from this object to the clone

      return clone;
   }
}

然后你打电话

MyObject someObjInstance = new MyObject();
...
...
MyObject clone = ((ICloneable)someObjInstance).Clone();
...

您将获得一个全新的对象,其中包含您需要的复制成员。我没有看到您提到的设置的好处,因为实现Clone()的类将知道要复制的内容。

这取决于您当然的具体目的。这将意味着创建新实例,而不是像MemberwiseClone()那样进行逐位复制。

答案 4 :(得分:0)

如果您的界面Settings为空(没有属性或方法),我会称之为代码味道。按照惯例,接口应以字母“I”或ISettings开头。

您如何实施方法applySettings(Settings s)?正如您所说,Settings接口为空,除非您将其转换为其他对象,否则您无法对s参数执行任何操作。这很糟糕,或者更好地描述为“无意义”,因为参数是强类型的,但忽略了强类型。

此外,我认为没有充分理由采用applySettings()方法。如果您有一个对象,并且第二个对象具有您需要的值,则只需使用第二个对象。如果正在使用第二个对象(在某些其他对象图中),则复制它并使用它。应该没有理由编写“使此对象成为另一个对象的副本”的逻辑,因为您必须已经编写了“制作副本”。

从客户的角度来看,制作深层副本应该很容易。 ICloneable界面非常适合这种情况。作为设计模式,这被称为 Prototype 模式。如果您需要不同的方法来创建副本(即不同类型的深层复制操作),您可以考虑使用构建器模式来实现Clone()方法