some thoughts of composite & visitor pattern

At first, let's look the typical class structure diagram of composite pattern:

 

Composite pattern is very suitable for Tree structure. The picture showed above defines a Interface Node and two sub concrete tree types  : Leaf  and Branch.  Branch may contains sub branch and leaf. The sample codes for the example are listed below:

public Interface Node{
       public void print();
}

public class leaf implements Node{
      public void print(){ 
             System.out.println("visit leaf...");
      }
}

public class branch implements Node{
       private List<Node> subNodes;

       public void addSubNode(Node subNode){}

       public void removeSubNode(Node subNode){}

       public void print(){
          for(Node node : subNodes){
               node.print();
          }
       }
}

 The code is so unpractical that the print method just show its node type. In a general way,  the requirement might  extended in two directions respectively: 

  • add new method for each node
  • add new node type in tree hierarchy.

under the first situation,  if we need print the number of  sub nodes  for each node, the easiest way, also the only way, is to  change the print method and plus new logic. That is to say, we need to modify the existed system to satisfy new requirement, which violate the open-closed principle of OOD. So, how can we do it with a  better way? May be a available method is to seperate the hebavior from the node class, namely introduce new class to response for behavior, and node class only contains state data.  So now, it is time that visitor pattern show its power.

the class diagram of visitor pattern as follows:

Compare to the diagram of composite pattern.  it has several extra classes : an integerface Visitor and class PrintVisitor. these classes provide the operation to visit nodes. The sample codes listed below:

public Interface Node{
       public void print();
       public void accept(Visitor v);
}

public class leaf implements Node{
      public void print(){ 
             System.out.println("visit leaf...");
      }
      public void accept(Visitor v){
             v.visit(this); 
      }
}

public class branch implements Node{
       private List<Node> subNodes;

       public void addSubNode(Node subNode){}

       public void removeSubNode(Node subNode){}

       public void print(){
          for(Node node : subNodes){
               node.print();
          }
       }
       public void accept(Visitor v){
             v.visit(this); 
      }
}

public interface Visitor{
      public void visit(Leaf leaf);
      public void visit(Branch branch);
}

public class PrintVisitor implements Visitor{
     public void visit(Leaf leaf){
            leaf.print();
     }
     public void visit(Branch branch){
            branch.print();
     }
} 

 Now, we can simply add a new 'visitor' class to extent node behavior, and need not any modification of existed system.  Visitor pattern works wonderfully here, but it also has some limitation.

  1. it only suitable for extending node behavior, not  for adding new node type in tree hierarchy. This is the fatal defect of visitor pattern. Just as we see from the simple codes,  a Visitor encapsulate the behavior of all nodes. So if one more node type is added, the vistor interface and all concrete classes need be modified to add corresponding behavior. Luckily, A variant of visitor pattern called 'acyclic visitor' pattern(avp for short) may solve the problem. The main idea of avp is make the Vistor Interface to be a Marker Interface, and create an corresponding visitor interface for each node type . So the codes using avp may looks like that:
    public Interface Node{
           public void print();
           public void accept(Visitor v);
    }
    
    public class leaf implements Node{
          public void print(){ 
                 System.out.println("visit leaf...");
          }
          public void accept(Visitor v){
                 LeafVisitor lv = (LeafVisitor)v;
                 lv.visit(this); 
          }
    }
    
    public class branch implements Node{
           private List<Node> subNodes;
    
           public void addSubNode(Node subNode){}
    
           public void removeSubNode(Node subNode){}
    
           public void print(){
              for(Node node : subNodes){
                   node.print();
              }
           }
           public void accept(Visitor v){
                 BranchVisitor lv = (BranchVisitor)v;
                 bv.visit(this); 
          }
    }
    
    public interface Visitor{}
    
    public interface LeafVisitor{
         public void visit(Leaf leaf);
    }
    
    public interface BranchVisitor{
        public void visit(Branch branch);
    }
    
    public class PrintVisitor implements Visitor,LeafVisitor,BranchVisitor{
         public void visit(Leaf leaf){
                leaf.print();
         }
         public void visit(Branch branch){
                branch.print();
         }
    } 
    
     In the 'accpet' method of class node class,  firstly, using up-casting, changes the argument to the visitor interface correspond with the node type. if success, then invokes the 'visit' method of the visitor.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值