复合模式
对于处理部分-整体层次结构非常有用。它有一个Component
接口(interface)。 Leaf
和 Composite
都提供 Component
接口(interface)的实现。
Add(Component c)
、Remove(Component c)
和 GetChild(intposition)
方法在 叶
类?
我可以让方法不执行任何操作,或者抛出异常,例如:OperationNotSuportedByLeafException
。 但是这样做会打破里氏替换原则。处理这些方法的最佳方法是什么?
编辑:另一种方法是在 Composite 中移动这些方法。它将是暴露的最顶层接口(interface),即组件。当需要调用 add
、remove
操作时,移动 Composite 中的方法将需要显式转换,这又违背了良好的设计原则。
最佳答案
当然取决于您的设计目标是什么。如果您的目标是树/图应该在任何时间点都可以修改,那么叶子实际上可以成为父节点。在这种情况下,可以在组件中定义与层次结构相关的方法。
另一种方法(虽然我不知道这是否适用于您的用例)是使用以下两个想法:
- 使结构不可变
- 将结构与功能分开
通过使结构不可变,我们可以将所有图构造推送到构造函数。这样我们就回避了您提到的类型转换问题,并且也使整个事情更容易推理。
通过将结构与功能分离,我们根本不需要向客户端发布结构信息,而是提供我们想要提供的功能。这样我们就可以保留 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
);
关于java - 如何处理复合模式中的添加、删除功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37576120/