Несколько листовых проблем методов в составном шаблоне

На работе мы разрабатываем приложение PHP, которое было бы позже повторно запрограммировано в Java. С некоторыми элементарными знаниями Java мы пытаемся разработать все, чтобы быть легко переписанными без любых головных болей. Интересная проблема вышла, когда мы пытались реализовать составной шаблон с огромным количеством методов в листах.

Что является нами пытающийся достигнуть (не использующие интерфейсы, это - просто быстрый пример):

class Composite {
    ...
}


class LeafOne {
    public function Foo( );

    public function Moo( );
}


class LeafTwo {
    public function Bar( );

    public function Baz( );
}


$c = new Composite( Array( new LeafOne( ), new LeafTwo( ) ) );

// will call method Foo in all classes in composite that contain this method
$c->Foo( );

// same with Bar
$c->Bar( );

Это походит в значительной степени на классический Составной шаблон, но проблема состоит в том, что у нас будет вполне много листовых классов, и у каждого из них могло бы быть ~5 методов (которых немногие могли бы отличаться, чем другие). Одно из наших решений, которое, кажется, лучший до сих пор и могло бы на самом деле работать, использует __, называют волшебный метод для вызова методов в листах. К сожалению, мы не знаем, существует ли эквивалент его в Java.

Таким образом, фактический вопрос: существует ли лучшее решение для этого, с помощью кода, который был бы в конечном счете легко повторно кодирован в Java? Или Вы рекомендуете какое-либо другое решение? Возможно, существует некоторый другой, лучший шаблон, который я мог использовать здесь.

В случае, если существует что-то неясное, просто спросите, и я отредактирую это сообщение.

Править:

Фактическая проблема состоит в том, что не каждый листовой класс содержит, например, метод Baz. Если бы мы использовали простой foreach для вызова Baz в каждом классе, то он дал бы набор использования ошибок, поскольку существуют определенные классы, которые не содержат этот метод. Классическое решение состояло бы в том, чтобы иметь каждый метод от каждого листового класса, реализованного в Составной класс, каждого с различной реализацией. Но это сделало бы наш составной класс огромным и грязным с суммой методов, которые мы используем.

Таким образом, обычное решение было бы похоже на это (Составной класс):

class Composite implements Fooable, Bazable {
    ...

    public function Foo( ) {
        foreach( $this->classes as $class ) {
            $class->Foo( );
        }
    }

    public function Baz( ) {
        ...
    }
}

Для предотвращения нашего кода для становления реальной путаницей мы думали о чем-то как:

class Composite {
    ...

    public function __call( ) {
        // implementation
    }
}

Но мы не действительно уверены, является ли это хорошее решение и если уже существует что-то подобное также в Java (как спросили перед редактированием).

6
задан Ondrej Slinták 23 April 2010 в 11:46
поделиться

2 ответа

В 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.
    }
  }
}
2
ответ дан 17 December 2019 в 07:02
поделиться

Шаблон оформления посетителей - неплохое решение. Но вы должны учитывать возможные изменения в структуре, например Новый класс Leaf заставит вас реализовать applyVisitor и добавить метод visit * для каждого созданного вами посетителя. Таким образом, Visitor действительно помогает вам добавить поведение к структурированным объектам за счет того, что структура не меняется слишком часто. Если структура меняется часто, а алгоритмы не так сильно, вы можете рассмотреть возможность использования разных композитов для объектов с одинаковыми интерфейсами. Если вы хотите сделать это грязным способом, как вы это делаете сейчас в PHP, посмотрите API отражения Java. Хорошим решением будут динамические вызовы imho (как в Ruby или Python). Вы можете смоделировать их, но это потребует много работы ... Итак, мой ответ - осторожно используйте Visitor или рассматривайте разные Composites для объектов с разным поведением.

2
ответ дан 17 December 2019 в 07:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: