2015-09-19 41 views
0

我遇到过几种情况,其中有一个包含多个对象的父对象,以及一个子对象中的信息更改会影响其他对象。将一个子对象中的更改传播到另一个子对象

例如,请考虑以下情况:

interface IUniverse 
{ 
    IStorage ShirtStorage; 
    IList<IHuman> Humans; 
} 

Interface IStorage: 
{ 
    string Location; 
    int Capacity; 
    IList<IShirt> Items; 
} 

Interface IHuman 
{ 
    string Name; 
    int Age; 
    IList<IShirt> Shirts; 
} 

我想删除从ShirtStorage特定的衬衫在我的宇宙,但在同一时间,因为衬衣是从存在删除,它应该也可以从所有人身上移除。

我已经想到了3种方式来做到这一点:


首先,我们可以引入 Add(IClothing)Remove(IClothing)方法 IStorage<T>IHuman

interface IUniverse 
{ 
    IStorage ShirtStorage; 
    IList<IHuman> Humans; 
} 

Interface IStorage 
{ 
    string Location; 
    int Capacity; 
    IList<IShirt> Items; 
    **void Add(IShirt);** 
    **void Remove(IShirt);** 
} 

Interface IHuman 
{ 
    string Name; 
    int Age; 
    IList<IShirt> Shirts; 
    **void AddShirts(IShirt);** 
    **void RemoveShirts(IShirts);** 
} 

之后,的上述接口的实现不会有当从ShirtStorage去除其去除从所有人类特定衬衫引擎盖下任何东西。

这种设计的缺点是,每次程序员从宇宙中取出衬衫时,他都必须手动移除每个人的每一个参考。

也就是说,程序员必须知道宇宙的确切结构以便移除一件衬衫。在宇宙结构变得非常复杂的情况下,这样一个特定衬衫的参考可能会出现在IHuman以上,这可能被证明是错误和乏味的。


其次,我们同样Add(IShirt)Remove(IShirt)方法介绍给接口IStorageIHuman

interface IUniverse 
{ 
    IStorage<IShirt> ShirtStorage; 
    IList<IHuman> Humans; 
} 

Interface IStorage 
{ 
    string Location; 
    int Capacity; 
    IList<IShirt> Items; 
    **void Add(IShirt);** 
    **void Remove(IShirt);** 
} 

Interface IHuman 
{ 
    string Name; 
    int Age; 
    IList<ICShirt> Shirts; 
    **void AddShirt(IShirt);** 
    **void RemoveShirt(IShirt);** 
} 

。但是这一次,我们使用上述接口,一个实施有一些通知正在进行。也就是说,

class Storage : IStorage 
{ 
    IUniverse parentUniverse; 
    string Location; 
    int Capacity; 
    IList<IShirt> Items; 

    // ... Implementation for Add(IShirt item) is trivial 

    void Remove(IShirt item) 
    { 
     this.Items.Add(item); 
     foreach (IHuman human in this.parentUniverse) 
      foreach(IClothing clothing in human.Clothings) 
       if (clothing == item) 
        human.RemoveClothing(clothing); 
    } 
} 

事实上,把所有的通知,并在接口的实现,接口的消费者不会通过每一个可能的参考去一个特定的IShirt当他想将其删除从存在,因此在这个意义上与之前的解决方案相比使得它成为better

然而,缺点是这样的设计固有地导致了病态的谎言,并且违反了单一责任原则。如果程序员在ShirtStorage上调用Remove(IShirt),他不会意识到从哪里删除引用。

如果程序员希望使用Mediator模式编写GUI,他将不确定发送哪条通知消息。

哪些人确切地从他们身上取下衬衫,因此需要在GUI上更新一些反映属于特定人的衬衫清单的组件?如果我有一个Catalog班级,并且所有衬衫的名字都被删除了 - 是否不会删除对应于删除衬衫的条目(引擎盖下)?我是否也必须为我的目录更新相应的GUI组件?


第三,我们介绍Add(IShirt)Remove(IShirt)方法IUniverse代替:

interface IUniverse 
{ 
    IStorage ShirtStorage; 
    IList<IHuman> Humans; 
    void Add(IShirt); 
    void Remove(IShirt); 
} 

Interface IStorage: 
{ 
    string Location; 
    int Capacity; 
    IList<IShirt> Items; 
} 

Interface IHuman 
{ 
    string Name; 
    int Age; 
    IList<IShirt> Shirts; 
} 

通过这样做,我们强迫接口的消费者接受,取消衬衫不仅影响衬衫存储,但其他成员IUniverse也是如此。

但是,其缺点与第二种解决方案中的不同。最重要的是,IUniverse实例最终成为了某种上帝对象。我需要从宇宙中移除一件衬衫的每一个地方,我都必须参考宇宙。

如果某个特定的GUI组件只是想显示ShirtStorage的信息并允许与存储进行交互(即添加和删除衬衫),是不是会在GUI组件和Universe之间引入一些耦合,唯一应该存在的耦合是GUI组件和IStorage


我写了几个应用程序使用了所有三种解决方案的组合。事实上,在不同的情况下,某些解决方案看起来比其他解决方案更好,但不一致性是一种痛苦,因为在从一种设计切换到另一种设计时,我几乎总是忘记做某些事情。

回答

5

每当我在oop的背景下听到“Propagating Changes”一词时,我立即想到Observer pattern。因此,我不会将责任交给域对象来“同步”添加和删除衬衫,而是会引入另一个承担此责任的类,并让您的域对象引发相关事件。而且你也一直坚持单一责任原则。

HTH

相关问题