OO设计模式:如何动态添加方法?

时间:2014-11-26 20:44:03

标签: java c# oop design-patterns

我在C#(或Java,并不重要)中实现了一个简单的树结构,其中所有内容都围绕着抽象类Node和它的一些子类。 Node提供与数学图论相关的方法和属性。例如,Node.Parent引用父节点和Node.Children子节点

class Node {  
    Node Parent;  
    Node[] Children;

    void appendNode(Node node) { ... }
}  

我正在使用树来执行计算。计算涉及大量递归,我还需要为每个节点存储中间值。对于每个计算,我已经向Node类引入了其他属性和方法,例如

class Node {  
    Node Parent;  
    Node[] Children; 

    // Calculate weight
    int weight; // current weight
    void recalculateWeight() {
        // perform some heavily recursive stuff
        // involving Parent.recalculateWeight()
        // and update the value of the variable weight
    }

    int price; // current price 
    void recalculatePrice() {
        // perform some heavily recursive stuff
        // involving Parent.recalculatePrice()
        // and update the value of the variable price
    }

    void appendNode(Node node) {
        // ...
        recalculateWeight();
        recalculatePrice();
    }
} 

但现在我不得不放弃这种方法,因为应该动态添加计算值而不更改Node类。动态意味着其他人应该能够仅依靠"图形理论方法在给定的树上实现自己的计算。 Node类。

你知道什么是好的设计模式吗?

2 个答案:

答案 0 :(得分:6)

这会尖叫Visitor模式。

interface Visitor{

    visit(Node node);

}

class Node{

   //...


   void accept(Visitor v){
       //feel free to change visit order to viist children first
       v.visit(this);
       for(Node child : children){
          v.visit(child);
       }

   }
}

然后,您可以将所有不同的计算用于不同的访问者。创建新类型的计算或遍历并不会更改Node类。您只需创建一个新的访客实施。

class WeightVisitor implements Visitor{

   int weight = 0;

   void visit(Node n){
        weight += ...
   }

}

然后每当你想计算重量

WeightVisitor visitor = new WeightVisitor();

rootNode.accept(visitor);

int weight = visitor.getWeight();

答案 1 :(得分:0)

这取决于你想要达到的目标。使用节点图有两种不同的方法:

  • 节点只是数据的容器,节点库的用户可以使用它们来存储数据并计算各种事物。这类似于LinkedList,它允许您在节点中存储数据,遍历列表,删除节点等。甚至递归。但这不需要对节点本身进行任何更改。这些方法完全由客户负责在外部实施。您的节点应该只提供以各种方式迭代它们的方法。并且可能提供类型安全(即类似List<Type>的通用)方式来存储自定义数据。

  • 您正在为用户定义的节点提供图表。用户将以自定义方式扩展Node类以执行自定义操作。用户仍将使用您提供的图形功能,例如您可以提供的Tree.rebalance(Node root)方法。您的节点类和其他方法应该允许的是使扩展变得容易。

例如,您应该考虑使类和其他方法通用,以便用户可以完全使用自定义子类型

// That's what you provide. Has all the base functionality of a node
class Node<T extends Node<T>> {
    private T parent;
    private List<T> children;
    public void setParent(T parent) {
        this.parent = parent;
    }
    public T getParent() {
        return this.parent;
    }
    // ...
}

// that's what the user can do with it
class WeightedNode extends Node<WeightedNode> {
    public int weight = 5;

    public void update() {
        WeightedNode parent = getParent();
        // ^^ Typesafe access to WeightedNode!
        this.weight = parent.weight + 1;
        parent.update();
    }
}

class User {
    void use() {
        WeightedNode node = new WeightedNode();
        node.update();
    }
}