Ond*_*ták 6 php java design-patterns
在工作中,我们正在开发一个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( );
Run Code Online (Sandbox Code Playgroud)
它似乎是非常经典的复合模式,但问题是我们将拥有相当多的叶类,并且它们中的每一个可能有~5种方法(其中很少可能与其他方法不同).我们的解决方案之一似乎是迄今为止最好的解决方案,可能实际上正在使用__call魔术方法来调用叶子中的方法.不幸的是,我们不知道Java中是否有相同的东西.
所以实际的问题是:有没有更好的解决方案,使用最终可以轻松重新编码为Java的代码?或者您推荐任何其他解决方案?也许我可以在这里使用一些不同的,更好的模式.
如果有不清楚的地方,请询问,我将编辑这篇文章.
编辑:
实际问题是并非每个叶类都包含例如方法Baz.如果我们使用简单的foreach在每个类中调用Baz,它会使用一堆错误,因为某些类不包含此方法.经典的解决方案是将每个叶子类中的每一个方法都实现为Composite类,每个方法都有不同的实现.但这会使我们的复合类庞大而且混乱我们使用的方法量.
所以通常的解决方案看起来像这样(Composite类):
class Composite implements Fooable, Bazable {
...
public function Foo( ) {
foreach( $this->classes as $class ) {
$class->Foo( );
}
}
public function Baz( ) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
为了防止我们的代码变得混乱,我们考虑的事情如下:
class Composite {
...
public function __call( ) {
// implementation
}
}
Run Code Online (Sandbox Code Playgroud)
但我们并不确定它是否是一个很好的解决方案,如果在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.
}
}
}
Run Code Online (Sandbox Code Playgroud)