是复合模式结实吗?(Is the Composite Pattern SOLID?)

2019-08-19 07:51发布

叶在综合模式实现了Component接口,包括AddRemoveGetChild方法是叶是永远不会使用。 这似乎是违反接口隔离原则的。

所以是组合模式的使用SOLID ?

链接组合模式: http://www.dofactory.com/Patterns/PatternComposite.aspx

Answer 1:

在为您的链接和大多数书籍中描述的模式真正的气味是Component具有的方法Composite 。 我想这大概是因为该模式是相当老,并一直重复这样多年。 我的观点是,只有Composite要有相关的合成的任何方法。

我曾经转换棋盘游戏到电脑游戏。 棋子放在地图地球的,划分为六边形上。 所有的六边形的99%表示的单一位置。 不幸的是,一些六边形的包含多个位置,例如,一些原本里面他们夫妇岛屿。 我使用的复合物的图案来代表这些位置,但不能作为你的链接描述。 它是这样的(在Java中):

public interface Location {
   Set<Army> getArmies();
}

public class SingleLocation implements Location {

   public Set<Army> getArmies() {
      return armies ;
   }

   private Set<Army> armies = new HashSet<Army>();
}

public class CompositeLocation implements Location {

   public Set<Army> getArmies() {

      Set<Army> armies = new HashSet<Army>();

      for(Location subLocation: subLocations) {
         armies.addAll(subLocation.getArmies());
      }

      return armies;
   }

   public void addSubLocation(Location location) {
      subLocations.add(location);
   }

   private Set<Location> subLocations = new HashSet<Location>();
}

请注意,只有Composite了合成方法,甚至不公开,它有孩子大部分客户的事实(在这个例子中,客户只希望从一个位置军队的名单-事实上,他们在许多子位置是无关紧要的)。

请记住,设计模式并不设置在石头的东西,你必须实现准确。 把它们当作食谱。 当您按照食谱做饭时,你当然可以只严格地遵守它。 然而,有些厨师会扔在配方自己的曲折。 其他人会连看都不看,因为他们是专家,可以在配方的精神一起扔东西,甚至没有考虑它。 这同样适用于设计模式。 他们是有延展性的食谱。

你也可以把这些SOLID原则太远。 如果你读罗伯特·马丁的文章,他指出,全线应用这些原则没有任何的思想会产生过于复杂的代码。 软件通过一系列的取舍和balancings的设计 - 有时你放弃纯实木,因为它产生较少的清洁复杂的代码。 如果你使你的代码完全封装,灵活,分离等,你会发明了一种新的编程语言:-)



Answer 2:

我要说的是,在您的链接描述的复合模式违反了里氏替换原则 ,五大一个SOLID原则。

Component有方法,只有有意义的CompositeAdd() Leaf从继承Component ,因此将有一个Add()像任何其他方法Component 。 但是Leafs没有孩子,所以下面的方法调用不能返回有意义的结果:

myLeaf.Add( someChild );

该呼叫将不得不抛出一个MethodNotSupportedException ,返回null在一些其他的方式给调用者,添加一个孩子到一个或指示Leaf没有意义。

因此,你不能这样对待一个Leaf像任何其他Component ,因为如果你尝试,你会得到一个异常。 在里氏substition原则规定:

设q(x)为可证明的关于对象的属性类型T.则Q(Y)的X应为S型的对象ý真其中S是T的子类型

Components有,您可以添加孩子给他们的财产。 但你不能孩子添加到Leaf ,尽管Leaf是一个亚型Component ,它违反了原则。



Answer 3:

GOF的书167页专门解决这个问题。

虽然综合类实现AddRemove管理儿童行动,在综合模式的一个重要问题是哪些类声明这些行动......如果我们在组件声明这些操作,让他们有意义的叶类,或者我们应该声明只有在综合定义呢?

该决定涉及安全与透明度之间的权衡:

  • 在类层次结构的根定义子管理界面使您的透明度,因为你可以均匀地处理所有组件。 它的成本你的安全,但是,因为客户可以尝试做毫无意义的事情一样添加和叶删除对象。
  • 在综合类定义孩子的管理,给您安全,因为任何试图从叶子中添加或删除对象将在编译时在C ++等静态类型语言被抓。 但你失去透明度,因为叶片和复合材料具有不同的接口。

我们已经在这种模式强调了安全的透明度。

最后一句是,模式违反类型安全原则的承认。 以固体计,这将主要是LSP,但可能ISP为好。 请注意,“ 声明其子类不使用方法 ”是ISP的过于简单化。 这些未使用的方法,真正的危险是,他们将要求其子类并不需要额外的依赖,模块之间的耦合增加。



Answer 4:

使用复合材料让你来均匀地处理所有对象,并可能摆脱这是一个代码味道的一个明显标志“}这种”事。 所以它的第一眼尊重到LSP(里氏的)。 然而,正如你区分常见的方法实现,很可能开始违反LSP。 因此,国际海事组织,我们需要保持这种平衡。



文章来源: Is the Composite Pattern SOLID?