◎ 節點類的設計
·特征分析
數據特征:名字、節點值、節點的屬性、節點的父節點、節點下的子節點、參照對象等特點
行為特征:得到節點名、節點值、子節點、節點的屬性、參照對象
增加子節點、屬性、參照對象
刪除子節點、屬性
設置父節點
判斷節點是否為空(沒有值且沒有子節點和屬性)
遍歷節點及節點下的所有子節點(以及子節點下的子節點)
對于像子節點、屬性這類可以有多個對象的數據,應提供
根據名字獲取節點集合的操作;獲取所有節點集合的操作;獲取某位置的節點;遍歷所有節點;獲取集合數量
另外,子節點和節點具有共同的特征,只是子節點是節點的集合,如上所述,同時子節點有一些集合所特有的操作;
屬性則是節點的一個子集,具有名字、值、父節點,可以當作節點來處理。
·類設計
節點類Node
子節點類SubNodes
另外為了在遍歷過程中,可以針對所遍歷的每個節點執行自定義的動作,提供NodeVisit接口
同時提供NodeVisit接口的適配NodeVisitAdaptor
·遍歷的問題
首先執行節點的訪問Node.visit,然后在Node.visit方法中調用子節點SubNodes.visit方法,在SubNodes.visit方法中對集合中的
所有節點(Node),調用Node.visit,這樣就實現了給定節點及該節點下面所有節點的遍歷。
原理:實際上是一種互調。即在A類對象中調用B類對象的方法,同時又在B類對象的同一個方法中調用A類對象的方法。
A類和B類的約束,A類包含一個B類對象,B類包含了A類對象的集合,A類對象和B類對象擁有同樣的調用方法visit(也可以是其它名字)。
這樣當A調用B的方法時,B遍歷所有的A并調用A的方法,由此實現了遍歷訪問。
最后,請記住遍歷的對象應該是相同的類對象。
·框架
public class Node{
private String ms_Name;
private Object mo_Value;
private SubNodes msn_Children;
private SubNodes msn_Attributes;
public String getName();
public Object getValue();
public void setParentNode(Node);
public void addChild(Node);
public int getChildrenCount();
public int getChildrenCount(String childName)
public List getChildren();
public List getChildren(String childName);
public Node getChild(int index);
public boolean removeChild(Node);
public boolean removeChildren(String childName);
public boolean removeChildren();
public void addAttribute(Node);
public int getAttributeCount();
public int getAttributeCount(String attrName)
public List getAttributes();
public List getAttributes(String attrName);
public Node getAttribute(int index);
public boolean removeAttribute(Node);
public boolean removeAttributes(String attrName);
public boolean removeAttributes();
public boolean isAttribute();//檢查節點是否是一個屬性節點
public boolean isDefined();//節點是否定義過,即節點有值或有子節點
public void visit(NodeVisit);
protected static class SubNodes{
private List ml_nodes;//子節點
private Map mm_namedNodes;//子節點名字與子節點鏈表的映射,即多個子節點可以有相同的名字
public void addNode(Node);
public boolean removeNode(Node);
public boolean removeNodes(String);
public void clear();
public ConfigurationNode getNode(int index);
public List getSubNodes();//返回所有子節點
public List getSubNodes(String name);
public void visit(NodeVisit)
}
}
public interface NodeVisitor{
void visitBeforeChildren(ConfigurationNode node);//在該節點的所有子節點被處理之前,訪問該節點
void visitAfterChildren(ConfigurationNode node);//在該節點的所有子節點被處理之后,訪問該節點
boolean terminate();//結束標識,通知訪問方法是否結束。通過該標識,可以實現某種搜索策略。
}
·Jarkarta開源的實現片段
public class DefaultConfigurationNode implements ConfigurationNode, Cloneable{
public void addChild(ConfigurationNode child)//增加子節點
{
children.addNode(child);
child.setAttribute(false);
child.setParentNode(this);//設置父節點
}
public void addAttribute(ConfigurationNode attr){//增加屬性
attributes.addNode(attr);
attr.setAttribute(true);
attr.setParentNode(this);
}
public boolean isAttribute(){//節點是否是屬性節點
return attribute;
}
public void setAttribute(boolean f){//設置節點是否是屬性節點
checkState();
attribute = f;
}
public boolean isDefined(){//節點是否已經定義
return getValue() != null || getChildrenCount() > 0
|| getAttributeCount() > 0;
}
public void visit(ConfigurationNodeVisitor visitor){//遍歷節點
if (visitor == null){
throw new IllegalArgumentException("Visitor must not be null!");
}
if (!visitor.terminate()){
visitor.visitBeforeChildren(this);//執行自定義訪問動作
children.visit(visitor);//調用子節點的visit,從而實現了該節點下面所有節點的遍歷
attributes.visit(visitor);
visitor.visitAfterChildren(this);//執行自定義訪問動作
}
}
public Object clone(){//淺克隆,因為克隆后子節點和屬性都進行了初始化
try{
DefaultConfigurationNode copy = (DefaultConfigurationNode) super
.clone();
copy.initSubNodes();
return copy;
}catch (CloneNotSupportedException cex){
return null; // should not happen
}
}
protected void checkState(){
if (getParentNode() != null){
throw new IllegalStateException(
"Node cannot be modified when added to a parent!");
}
}
protected SubNodes createSubNodes(boolean attributes){//創建子節點
return new SubNodes();
}
private void initSubNodes(){//初始化子節點和屬性
children = createSubNodes(false);
attributes = createSubNodes(true);
}
protected static class SubNodes{//內部類,幫助DefaultConfigurationNode管理子節點
private List nodes;
private Map namedNodes;
public void addNode(ConfigurationNode node){//增加一個子節點
if (node == null || node.getName() == null){
throw new IllegalArgumentException(
"Node to add must have a defined name!");
}
node.setParentNode(null); //設置為空,由DefaultConfigurationNode的addChild來完成setParent
if (nodes == null){
nodes = new ArrayList();
namedNodes = new HashMap();
}
nodes.add(node);
List lst = (List) namedNodes.get(node.getName());
if (lst == null){
lst = new LinkedList();//鏈表結構
namedNodes.put(node.getName(), lst);
}
lst.add(node);
}
public boolean removeNode(ConfigurationNode node){//刪除一個子節點
if (nodes != null && node != null && nodes.contains(node)){
detachNode(node);
nodes.remove(node);
List lst = (List) namedNodes.get(node.getName());
if (lst != null){
lst.remove(node);
if (lst.isEmpty()){
namedNodes.remove(node.getName());
}
}
return true;
}else{
return false;
}
}
public boolean removeNodes(String name){//清除所有名字為name的子節點
if (nodes != null && name != null){
List lst = (List) namedNodes.remove(name);
if (lst != null){
detachNodes(lst);
nodes.removeAll(lst);
return true;
}
}
return false;
}
public void clear(){//清除所有子節點
if (nodes != null){
detachNodes(nodes);
nodes = null;
namedNodes = null;
}
}
public ConfigurationNode getNode(int index){//取第index個子節點index從0開始
if (nodes == null)
{
throw new IndexOutOfBoundsException("No sub nodes available!");
}
return (ConfigurationNode) nodes.get(index);
}
public List getSubNodes(){//取所有子節點
return (nodes == null) ? Collections.EMPTY_LIST : Collections
.unmodifiableList(nodes);
}
public List getSubNodes(String name){//取所有名字為name的子節點
if (name == null){//如果name為空返回所有子節點
return getSubNodes();
}
List result;
if (nodes == null){
result = null;
}else{
result = (List) namedNodes.get(name);
}
return (result == null) ? Collections.EMPTY_LIST : Collections
.unmodifiableList(result);
}
public void visit(ConfigurationNodeVisitor visitor){//遍歷所有子節點
if (nodes != null)
{
for (Iterator it = nodes.iterator(); it.hasNext()
&& !visitor.terminate();)
{
((ConfigurationNode) it.next()).visit(visitor);//通過與Node的配合實現了遍歷功能
}
}
}
//刪除一個子節點時調用此方法,確保被刪除節點的父對象被置空(reset),同時清除被刪除節點所有的引用
protected void detachNode(ConfigurationNode subNode){
subNode.setParentNode(null);
if (subNode instanceof DefaultConfigurationNode){
((DefaultConfigurationNode) subNode).removeReference();
}
}
protected void detachNodes(Collection subNodes){
for (Iterator it = subNodes.iterator(); it.hasNext();){
detachNode((ConfigurationNode) it.next());
}
}
}
}
·遍歷調用的例子
protected static void clearReferences(ConfigurationNode node){//清除所有的引用
node.visit(new ConfigurationNodeVisitorAdapter(){//匿名實現
public void visitBeforeChildren(ConfigurationNode nodeClearRef){
nodeClearRef.setReference(null);
}
});
}
posted on 2009-02-24 15:30
小橋流水人家 閱讀(751)
評論(0) 編輯 收藏 所屬分類:
java