Java 复合模式中的多叶方法问题

Java 复合模式中的多叶方法问题,java,php,design-patterns,Java,Php,Design Patterns,在工作中,我们正在开发一个PHP应用程序,稍后将重新编程为Java。有了Java的一些基本知识,我们正试图设计出可以轻松重写的所有东西,而不会让人头疼。当我们尝试在leafs中使用大量方法实现时,出现了一个有趣的问题 我们想要实现什么(不使用接口,这只是一个简单的例子): 这看起来非常经典的复合模式,但问题是我们将有相当多的叶类,每个叶类可能有5个方法(其中很少有方法可能与其他方法不同)。我们的一个解决方案,似乎是迄今为止最好的解决方案,实际上可能是可行的,就是使用调用leafs中的方法。 不幸

在工作中,我们正在开发一个PHP应用程序,稍后将重新编程为Java。有了Java的一些基本知识,我们正试图设计出可以轻松重写的所有东西,而不会让人头疼。当我们尝试在leafs中使用大量方法实现时,出现了一个有趣的问题

我们想要实现什么(不使用接口,这只是一个简单的例子):

这看起来非常经典的复合模式,但问题是我们将有相当多的叶类,每个叶类可能有5个方法(其中很少有方法可能与其他方法不同)。我们的一个解决方案,似乎是迄今为止最好的解决方案,实际上可能是可行的,就是使用调用leafs中的方法。 不幸的是,我们不知道Java中是否有与之相当的版本

因此,实际的问题是:是否有更好的解决方案,使用最终可以轻松地重新编码到Java中的代码?或者你推荐其他解决方案吗?也许有一些不同的,更好的模式,我可以在这里使用

如果有什么不清楚的地方,尽管问,我会编辑这篇文章

编辑:

实际的问题是,并不是每个叶类都包含方法Baz。如果我们在每个类中使用simpleforeach调用Baz,它会给use带来大量错误,因为某些类不包含此方法。经典的解决方案是将每个叶类中的每个方法实现为复合类,每个方法都有不同的实现。但这会使我们的复合类变得庞大而混乱,因为我们使用了大量的方法

所以通常的解决方案如下所示(复合类):

为了防止我们的代码变得一团糟,我们考虑了以下内容:

class Composite {
    ...

    public function __call( ) {
        // implementation
    }
}

但我们不确定这是否是一个好的解决方案,Java中是否也有类似的解决方案(正如编辑之前所问)在java中,您可以考虑使用将访问者对象传递给树中每个节点的模式,并且节点对访问者类产生<强>回调< /强>,以确定应该执行哪种行为。 这样可以避免任何强制转换或显式检查每个节点的类型

/**
 * Visitor capable of visiting each node within a document.
 * The visitor contains a callback method for each node type
 * within the document.
 */
public interface DocumentNodeVisitor {
  void visitWord(Word word);
  void visitImage(Image img);
}

/**
 * Base interface for each node in a document.
 */
public interface DocumentNode {
  void applyVisitor(DocumentVisitor v);
}

/**
 * Conrete node implementation representing a word.
 */    
public class Word implements DocumentNode {
  private final String s;

  public Word(String s) { this.s = s; }

  public String getValue() { return this.s; }

  public void applyVisitor(DocumentVisitor v) {
    // Make appropriate callback to visitor.
    v.visitWord(this);
  }
}

/**
 * Conrete node implementation representing an image.
 */        
public class Image implements DocumentNode {
  public void applyVisitor(DocumentVisitor v) {
    // Make appropriate callback to visitor.
    v.visitImage(this);
  }
}

public class Paragraph implements DocumentNode {
  private final List<DocumentNode> children;

  public Paragraph() {
    this.children = new LinkedList<DocumentNode>();
  }

  public void addChild(DocumentNode child) {
    // Technically a Paragraph should not contain other Paragraphs but
    // we allow it for this simple example.
    this.children.add(child);
  }

  // Unlike leaf nodes a Paragraph doesn't callback to
  // the visitor but rather passes the visitor to each
  // child node.
  public void applyVisitor(DocumentVisitor v) {
    for (DocumentNode child : children) {
      child.applyVisitor(v);
    }
  }
}    

/**
 * Concrete DocumentVisitor responsible for spell-checking.
 */
public class SpellChecker implements DocumentVisitor
  public void visitImage(Image i) {
    // Do nothing, as obviously we can't spellcheck an image.
  }

  public void visitWord(Word word) {
    if (!dictionary.contains(word.getValue()) {
      // TODO: Raise warning.
    }
  }
}
/**
*能够访问文档中每个节点的访问者。
*访问者包含每个节点类型的回调方法
*在文件中。
*/
公共接口DocumentNodeVisitor{
无效visitWord(Word);
无效可视图像(图像img);
}
/**
*文档中每个节点的基本接口。
*/
公共接口文档节点{
无效申请者(文件访问者v);
}
/**
*表示单词的Conrete节点实现。
*/    
公共类Word实现DocumentNode{
私有最终字符串s;
公共字(字符串s){this.s=s;}
公共字符串getValue(){返回this.s;}
公共无效应用访问者(文档访问者v){
//对来访者进行适当的回访。
v、 visitWord(本);
}
}
/**
*表示图像的Conrete节点实现。
*/        
公共类映像实现DocumentNode{
公共无效应用访问者(文档访问者v){
//对来访者进行适当的回访。
v、 探视(本);
}
}
公共类段落实现DocumentNode{
私人最终名单儿童;
公开段(){
this.children=newlinkedlist();
}
public void addChild(DocumentNode子节点){
//从技术上讲,段落不应包含其他段落,而应包含
//我们允许它用于这个简单的例子。
this.children.add(child);
}
//与叶节点不同,段落不会回调到
//而是将访客传递给每个人
//子节点。
公共无效应用访问者(文档访问者v){
for(DocumentNode子节点:子节点){
儿童应用鉴别器(v);
}
}
}    
/**
*负责拼写检查的具体文档访问者。
*/
公共类拼写检查器实现DocumentVisitor
公共空间访问(图一){
//什么也不做,因为我们显然不能检查图像的拼写。
}
公共无效访问(Word){
如果(!dictionary.contains(word.getValue()){
//TODO:发出警告。
}
}
}

访问者设计模式是一个很好的解决方案。但是你必须考虑结构中可能发生的变化,例如,新叶类将使你实现Apple访问者和向你创建的其他访问者添加Advest*方法。因此访问者真的帮助你以不改变结构的价格向结构化对象添加行为。如果结构经常变化,算法也不多,那么你可以考虑对同一个对象有不同的复合材料。如果你想用PHP中的脏方法做它,看看java反射API。很好的解决方案是IMO动态调用(如Ruby或Python)。你可以模拟这些,但是这会有很大的作用…所以我的答案是使用关心的访问者或者考虑不同行为的对象的不同的复合材料。< /P>请更好地描述这个问题。复合模式是与多个对象交互的,就像它们是一个或一样的,不管它们组成的结构。你想使用复合模式实现吗?我很想知道你为什么不从一开始就用Java来实现。@Gabriel:Edited。希望能有所帮助。@Ionut:Corporaty:)

class Composite {
    ...

    public function __call( ) {
        // implementation
    }
}
/**
 * Visitor capable of visiting each node within a document.
 * The visitor contains a callback method for each node type
 * within the document.
 */
public interface DocumentNodeVisitor {
  void visitWord(Word word);
  void visitImage(Image img);
}

/**
 * Base interface for each node in a document.
 */
public interface DocumentNode {
  void applyVisitor(DocumentVisitor v);
}

/**
 * Conrete node implementation representing a word.
 */    
public class Word implements DocumentNode {
  private final String s;

  public Word(String s) { this.s = s; }

  public String getValue() { return this.s; }

  public void applyVisitor(DocumentVisitor v) {
    // Make appropriate callback to visitor.
    v.visitWord(this);
  }
}

/**
 * Conrete node implementation representing an image.
 */        
public class Image implements DocumentNode {
  public void applyVisitor(DocumentVisitor v) {
    // Make appropriate callback to visitor.
    v.visitImage(this);
  }
}

public class Paragraph implements DocumentNode {
  private final List<DocumentNode> children;

  public Paragraph() {
    this.children = new LinkedList<DocumentNode>();
  }

  public void addChild(DocumentNode child) {
    // Technically a Paragraph should not contain other Paragraphs but
    // we allow it for this simple example.
    this.children.add(child);
  }

  // Unlike leaf nodes a Paragraph doesn't callback to
  // the visitor but rather passes the visitor to each
  // child node.
  public void applyVisitor(DocumentVisitor v) {
    for (DocumentNode child : children) {
      child.applyVisitor(v);
    }
  }
}    

/**
 * Concrete DocumentVisitor responsible for spell-checking.
 */
public class SpellChecker implements DocumentVisitor
  public void visitImage(Image i) {
    // Do nothing, as obviously we can't spellcheck an image.
  }

  public void visitWord(Word word) {
    if (!dictionary.contains(word.getValue()) {
      // TODO: Raise warning.
    }
  }
}