![](/img/trans.png)
[英]Is it possible to use Java annotations, to achieve a similar functionality as a preprocessor
[英]How to write the best possible Java code for a similar Ruby functionality?
我有一些Java經驗,正在學習Ruby。 我遇到了如下的Ruby程序:
class Tree
attr_accessor :children, :node_name
def initialize(name, children=[])
@children = children
@node_name = name
end
def visit_all(&block)
visit &block
children.each {|c| c.visit_all &block}
end
def visit(&block)
block.call self
end
end
ruby_tree = Tree.new( "Ruby" ,
[Tree.new("Reia" ),
Tree.new("MacRuby" )] )
puts "Visiting a node"
ruby_tree.visit {|node| puts node.node_name}
puts
puts "visiting entire tree"
ruby_tree.visit_all {|node| puts node.node_name}
當我查看ruby語言的強大功能時,我想到了用Java編寫類似的代碼,如下所示:
public class Tree {
private String name;
private Tree[] children;
Tree(String name, Tree[] children) {
this.name = name;
this.children = children;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Tree[] getChildren() {
return children;
}
public void setChildren(Tree[] children) {
this.children = children;
}
public static void main(String[] args) {
Tree myTree = new Tree("Ruby", new Tree[] {
new Tree("Reia", new Tree[] {}),
new Tree("MacRuby", new Tree[] {}) });
myTree.visit();
myTree.visit_all();
}
public void visit() {
System.out.println(getName());
}
public void visit_all() {
visit();
for (Tree tree : children) {
tree.visit();
}
}
}
問題:我知道這里的Java版本不如Ruby靈活,是否可以像ruby一樣提供Java類似的功能來達到靈活性呢?
首先,請注意:該代碼絕對可怕。 它幾乎不提供封裝,它左右泄漏實現細節, Tree
對象無法維護其自己的不變式或狀態。 其次,它不會在所有 Ruby的集合框架集成。
結果,我的Java翻譯也同樣令人恐懼,並且也沒有與Java的收集框架集成。
與Ruby相比,您的Java代碼的兩個最大缺點是
String
,而在Ruby版本中,它可以是任何對象,甚至可以是同一棵樹中對象的混合,並且 第一個問題在Java中無法輕易解決。 您可以使集合具有通用性,以便它可以容納任何類型的元素,但是使其具有異構性(即能夠在同一集合中容納不同類型的元素)將需要很多工作。 因此,我堅持使用部分解決方案:使Tree
通用。
第二個問題可以通過使迭代器采用包含代碼的對象來解決。 畢竟,一類子例程與僅使用一個方法的對象基本相同。 (Java 8將減輕一些痛苦,我在代碼中包含了示例。)
import java.util.Collection;
import java.util.ArrayList;
interface Consumer<T> {
void accept(T e);
}
// In Java 8, this interface is already part of the JRE.
// Just replace the 3 lines above with this import:
//import java.util.function.Consumer;
class Tree<T> {
private String nodeName;
private Collection<Tree<T>> children = new ArrayList<>();
Tree(String name, Collection<Tree<T>> children) {
nodeName = name;
this.children = children;
}
Tree(String name) {
nodeName = name;
}
public String getNodeName() { return nodeName; }
public void setNodeName(String name) { nodeName = name; }
public Collection<Tree<T>> getChildren() { return children; }
public void setChildren(Collection<Tree<T>> children) { this.children = children; }
void visitAll(Consumer<Tree<T>> block) {
visit(block);
for (Tree<T> tree : children) tree.visitAll(block);
}
void visit(Consumer<Tree<T>> block) {
block.accept(this);
}
public static void main(String... args) {
ArrayList<Tree<String>> children = new ArrayList<>();
children.add(new Tree<String>("Reia"));
children.add(new Tree<String>("MacRuby"));
Tree<String> rubyTree = new Tree<>("Ruby", children);
System.out.println("Visiting a node");
rubyTree.visit(new Consumer<Tree<String>>() {
public void accept(Tree<String> node) {
System.out.println(node.getNodeName());
}
});
// In Java 8, you can use a lambda.
// Just replace the 5 lines above with this line:
//rubyTree.visit(node -> System.out.println(node.getNodeName()));
System.out.println();
System.out.println("Visiting entire tree");
rubyTree.visitAll(new Consumer<Tree<String>>() {
public void accept(Tree<String> node) {
System.out.println(node.getNodeName());
}
});
// In Java 8, you can use a lambda.
// Just replace the 5 lines above with this line:
//rubyTree.visitAll(node -> System.out.println(node.getNodeName()));
}
}
def visit(&block)
block.call self
end
更好地寫為
def visit
yield self
end
而且, visit_all
和visit
會更習慣地寫為符合Enumerable
模塊:
class Tree
include Enumerable
# ...
def each(&cb)
cb.call(@element)
children.each end |child|
child.each(&cb) if child.respond_to?(:each)
end
end
end
這樣,您可以免費獲得各種其他東西,例如max
...,而且,每個人都知道each
元素都會對所有元素應用一個塊,而他們將不得不仔細閱讀您的API文檔或代碼以查看該函數是否被調用visit_all
。
編輯 :因為我顯然是個白痴,所以刪除了一大塊。 感謝steenslag使我正確。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.