如何处理复合模式中的添加,删除功能?

时间:2016-06-01 18:22:17

标签: java oop design-patterns composite

Composite pattern对于处理部分整体层次结构非常有用。它有Component的界面。 LeafComposite都为Component接口提供了实现。

Add(Component c)课程中Remove(Component c)GetChild(int position)Leaf方法的实施应该是什么?

我可以使用方法不执行任何操作,或者抛出异常,例如:OperationNotSuportedByLeafException但是这样做会打破Liskov替代原则。处理这些方法的最佳方法是什么?

编辑:另一种方法是在Composite 中移动这些方法。它将是暴露的最顶层接口,即组件。当需要调用addremove操作时,在Composite中移动方法将需要显式转换,这又违反了良好的设计原则。

enter image description here

2 个答案:

答案 0 :(得分:2)

当然取决于您的设计目标。如果您的目标是树/图应该可以在任何时间点修改,那么叶子实际上可以成为父节点。在这种情况下,可以在组件中定义与层次结构相关的方法。

另一种方法(虽然我不知道这是否适用于您的用例)是使用以下两个想法:

  • 使结构不可变
  • 将功能与功能分开

通过使结构不可变,我们可以将所有图构造推送到构造函数。有了这个,我们回避你提到的类型转换问题,并使整个事情更容易推理。

通过将结构与功能分离,我们不需要向客户发布结构信息,而是提供我们想要提供的功能。有了这个,我们可以保留Liskov,Demeter和其他OO的东西。

这就是它的样子:

public interface Node {
    // Here we offer the "functionality", but we don't
    // publish the "structure". This is made-up, I
    // don't know your use-case.
    void process(Consumer<Payload> payloadConsumer);
}

public class Leaf implements Node {
    private Payload payload;

    public Lead(Payload payload) {
        this.payload = payload;
    }

    @Override
    public void process(Consumer<Payload> payloadConsumer) {
        payloadConsumer.accept(payload);
    }
}

public class ParentNode implements Node {
    private List<Node> children;

    public ParentNode(Node... children) {
        this.children = asList(children);
    }

    // Here we implement the processing recursively.
    // All children can respond according to their semantics,
    // instead of assuming any structure beyond what we know.
    @Override
    public void process(Consumer<Payload> payloadConsumer) {
       children.forEach(child -> child.process(payloadConsumer));
    }
}

当然,您可以根据要表示的逻辑类型定义自己的Node类型。您可以定义多个操作,而不仅仅是我编写的一个process()方法。然后你可以像这样把所有这些插在一起:

Node graph = new ParentNode(
   new ParentNode(new Leaf(p1), new Leaf(p2)),
   new SpecialLeaf(a, b, c) // Whatever
);

答案 1 :(得分:1)

有两种方法可以解决这个问题。

  1. 抛出OperationNotSuportedByLeafException。你可以辩论这是否会导致LSP。我个人认为应该避免它,但有时它是最好的解决方案(例如,参见Java的不可变列表)。 LSP是一个原则,旨在帮助您编写质量更好的代码。每个系统都有疣,这可能就是其中之一。

  2. 移动添加&amp;移至复合实体(example)。这是您通常在视图库中看到的内容。视图可以是文本块,也可以是包含许多其他视图的复杂布局。