【问题标题】:How to Design whether a Class Property has Changed?如何设计一个类属性是否发生了变化?
【发布时间】:2014-01-20 13:04:00
【问题描述】:

我有一个包含大约 20 个属性的类,但我会针对这个问题对其进行简化:

public class Product
{
   public int Id { get; set; }
   public string Name { get; set; }
}

我想要一个类或属性来标识我的类是否脏。我的意思是确定它的任何值是否发生了变化?

我可以采用 3 种设计方法:

1) 在类内部设置属性时,我检查属性是否为IsDirty。

public string Name 
{
    get { return this._name; }
    set { if (this._name != value) { this.IsDirty = true; this._name = value; }
}

2) 从类外设置属性时,我检查属性是否为 IsDirty。

例如

if (p.Name != newName)
{
 p.IsDirty = true;
 p.Name = newName; 
}

这种方法迫使我在客户端类中添加大量 if。有些属性甚至是集合,甚至是引用对象,所以行数会增加。

3) 当对象准备好保存时,我通过获取克隆对象并检查是否相等来检查是否有任何属性 IsDirty。

这会导致性能较差,因为我必须克隆或再次加载原始对象,然后一一比较属性。

哪一个是最好的设计?或者是否有任何其他设计模式可以帮助解决这个问题?

【问题讨论】:

  • 如果您更改值然后将其重置为原始值,则克隆检查和脏集没有相同的行为。克隆不会检测到“更改”。这是否是一个问题取决于您。

标签: c# .net visual-studio design-patterns


【解决方案1】:

另一种选择是实现INotifyPropertyChanged 接口。

请注意,这将帮助您使事情更整洁,让您的 API 更清晰,但至于内部实施有关跟踪更改后,仍由您来实施。我认为这与您的Option #1 最相配

【讨论】:

  • 我们的对象是用于将 NHibernate 映射到数据库表的业务实体。这就是为什么我不愿意把逻辑放在课堂上。我宁愿让课堂简单明了。
  • 我不同意。我觉得你太刻板了。界面是一个很好的方法。
  • INotifyPropertyChanged 方法不是一个坏主意,但它闻起来有点“推卸责任”。该对象只是引发事件说“我变了!”另一个对象现在负责跟踪脏污度。这意味着客户端代码现在不仅负责实例化对象,还负责将其连接到此侦听器。
  • @CSJ 对象本身可以注册到事件,并执行以下操作:this.isDirty = true; 这样对象将 a.保持跟踪 b。维护关于状态的非易失性指示。
  • @TheLight,我之前的评论也回答了你的评论吗?
【解决方案2】:

选项 1 显然是最好的:它将跟踪脏污的责任放在它所属的地方:在对象内部。选项 2 已退出,因为正如您所提到的,您将这个责任强加给您班级的客户。选项 3 存在您提到的性能问题。

顺便说一句,您应该使用DynamicProxy 研究代理实现。这将使您的代码看起来像这样:

public class Product
{
   public virtual int Id { get; set; }
   public virtual string Name { get; set; }
}

并且通过明智地使用拦截器,您可以获得您想要的行为。您可以编写一个拦截器来拦截任何“集合”并在其中执行一些逻辑,例如设置 IsDirty 标志。

【讨论】:

    【解决方案3】:

    另一个想法是将其设为GoF Observable 并让感兴趣的Observer 各方注册他们对更改的兴趣。这是一种更加基于事件的方法。

    【讨论】:

    • 使用观察者模式与方法 1 非常相似,因为检查和通知的逻辑将在每个属性内部。不确定这是否是最好的设计,因为它违反了 SRP。
    【解决方案4】:

    这是最好的解决方案,非常符合 SRP 原则,我创建了以下类:

    • ProductWithChangeDetection;这使用装饰器模式将此新功能添加到现有产品对象中

    • ProductChangeDetector;这包含检查和通知的逻辑。目前只公开 ChangeDetected 属性,但如果需要更多复杂性,则应实现 INotifyPropertyChange 接口。

    • ProductEquitable;这实现了 IEquitable 并有一些重载来检查两个对象/属性是否相等

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-28
      • 2014-07-06
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 2014-12-18
      • 1970-01-01
      相关资源
      最近更新 更多