2013-10-18 3 views
0

메모리에 그래프 네트워크를 생성하고 Dijkstra의 알고리즘을 사용하여 최단 경로 문제를 해결하는 시스템을 개발 중입니다. 서로를 참조하는 두 개의 클래스가 있습니다. ...Google Closure 라이브러리/컴파일러의 순환 종속성 오류를 방지하는 방법

// vertex.js 
goog.provide('Vertex'); 
goog.require('Edge'); 

/** 
* @constructor 
*/ 
Vertex = function(){ 
    this.edges_ = []; 
}; 

/** 
* @param {Edge} edge 
*/ 
Vertex.prototype.addEdge(edge){ 
    this.edges_.push(edge); 
}; 

/** 
* @return {Array.<Edge>} 
*/ 
Vertex.prototype.getAllEdges(){ 
    return this.edges_; 
}; 

예, 가장자리가 언급하는 정점 첫 번째는

// edge.js 
goog.provide('Edge'); 
goog.require('Vertex'); 

/** 
* @constructor 
*/ 
Edge = function(){ 
    this.vertices_ = []; 
}; 

/** 
* @param {Vertex} vertex 
*/ 
Edge.prototype.addVertex(vertex){ 
    this.vertices_.push(vertex); 
}; 

/** 
* @return {Array.<Vertex>} 
*/ 
Edge.prototype.getVertices(){ 
    return this.vertices_; 
}; 

이고, 다른 하나는, 정점 가장자리를 참조하고 있습니다. 나는 이것이 자연스러운 것이라고 생각한다.

순환 종속성을 포함하므로 이러한 코드를 컴파일 할 수 없다는 것이 문제입니다. here 순환 의존성을 포함하는 시스템 설계가 잘못되었다고하지만, 나는 결국 그 시스템의 잘못된 점을 발견 할 수 없다고 말합니다.

JavaScript로 최단 경로 문제를 해결할 수있는 응용 프로그램을 개발할 때 클로저 컴파일러를 사용하는 것은 잘못된가요? 대체 솔루션이 있습니까?

답변

1

가장자리는 참조 정점, 정점은 참조 가장자리입니다. 나는 이것이 자연스러운 것이라고 생각한다.

이것은 잘못된 가정입니다. 정점을 가장자리로 가리키는 자연스러운 것은 이 아니고, 정점을 가리키는 가장자리가 있습니다.입니다. 하나는 다른 하나를 참조해야하며 둘 다 서로를 참조하지는 않습니다. 참조 책임이 중복되면 모든 문제가 발생할 수 있습니다. 예를 들어, 동기화가되지 않으면 그래프를 다시 작성할 수있는 진실의 원천이 없습니다.

순환 의존성을 피하려면 관계의 "소유자"가 하나 있어야합니다. 특정 예에서, 정점을 참조 모서리은과 같이 "소유자"더 확실한 인상을 받았는데 그런 다음

// edge.js 
goog.provide('Edge'); 

goog.require('Vertex'); 
goog.require('goog.math.Coordinate'); 

/** 
* @constructor 
* @param {Vertex} start 
* @param {Vertex} end 
*/ 
Edge = function(start, end) { 
    /** 
    * @type {Vertex} 
    * @private 
    */ 
    this.start_ = start; 

    /** 
    * @type {Vertex} 
    * @private 
    */ 
    this.end_ = end; 
}; 

/** 
* @return {number} 
*/ 
Edge.prototype.getDistance = function() { 
    goog.math.Coordinate.distance(this.start_, this.end_); 
}; 

/** 
* Checks if this Edge connects to the referenced vertex. 
* @param {Vertex} vertex 
* @return {bool} 
*/ 
Edge.prototype.connects = function(vertex) { 
    return this.start_ === vertex || this.end_ === vertex; 
}; 

/** 
* @return {Vertex} 
*/ 
Edge.prototype.getStart = function() { 
    return this.start_; 
}; 

/** 
* @return {Vertex} 
*/ 
Edge.prototype.getEnd = function() { 
    return this.end_; 
}; 

그래프 ... ... 그런

// vertex.js 
goog.provide('Vertex'); 

goog.require('goog.math.Coordinate'); 

/** 
* @constructor 
* @param {number=} opt_x x-position, defaults to 0 
* @param {number=} opt_y y-position, defaults to 0 
* @extends {goog.math.Coordinate} 
*/ 
Vertex = function(opt_x, opt_y) { 
    goog.base(this, opt_x, opt_y); 
}; 

에지

/** 
* @param {Array.<Edge>} edges 
* @constructor 
*/ 
Graph = function(edges) { 

    /** 
    * @type {Array.<Edge>} 
    * @private 
    */ 
    this.edges_ = edges; 
}; 

/** 
* @param {Vertex} start 
* @param {Vertex} end 
* @return {number|undefined} shortest path between {@code start} and {@code end}, 
* with 'undefined' being returned if a path does not exist. 
*/ 
Graph.prototype.getShortestPath = function(start, end) { 
    return this.getShortestPath_(start, end, 0, []); 
} 

/** 
* @param {Vertex} start 
* @param {Vertex} end 
* @param {number} traveled amount traveled thus far 
* @param {Array.<Vertex>} path the route taken thus far 
* @return {number|undefined} 
* @private 
*/ 
Graph.prototype.getShortestPath_ = function(start, end, traveled, path) { 
    if (start == end) { 
     return traveled + 0; 
    } 

    var distances = goog.array.map(
     this.getEdgesToTry_(start, path), 
     function (edge) { 
      var nextStart; 

      if (edge.getStart() === start) { 
       nextStart = edge.getEnd(); 
      } else { 
       nextStart = edge.getStart(); 
      } 

      return this.getShortestPath_(
       newStart, 
       end, 
       edge.getDistance() + traveled, 
       goog.array.concat(path, start) 
      ); 
     }, 
     this 
    ); 

    return goog.array.reduce(
     distances, 
     function (shortestDistance, distance) { 
      if (distance !== undefined) { 
       if (shortestDistance === undefined) { 
        return distance; 
       } else { 
        return Math.min(shortestDistance, distance); 
       } 
      } else { 
       return shortestDistance; 
      } 
     }, 
     undefined 
    );  
}; 

/** 
    * @param {Vertex} vertex 
    * @param {Array.<Vertex>} path 
    * @return {Array.<Vertex>} 
    * @private 
    */ 
Graph.prototype.getEdgesToTry_ = function(vertex, path) { 
    return goog.array.filter(
     this.edges_, 
     function (edge) { return this.isEdgeToTry_(edge, vertex, path); }, 
     this 
    );   
}; 

/** 
    * @param {Edge} edge 
    * @param {Vertex} start 
    * @param {Array.<Vertex>} path 
    * @return {bool} 
    * @private 
    */ 
Graph.prototype.isEdgeToTry_ = function(edge, start, path) { 
    return edge.connects(start) 
     && goog.array.every(
      path, function(vertex) { return !edge.connects(vertex); }); 
}; 

경고 : 나는 이것을 시험하지 않았다. 그것은 some nice Puerto Rican rum 병을 통해 해킹 한 것입니다. 아마 여기 저기에 뭔가 엉망이 될 수도 있습니다. 그럼에도 불구하고, 개념은 의미한다. 그래프에 대한 질문에 답하기 위해 특정 언어 나 기술에 순환 종속성이 필요하지는 않습니다 (솔직히 바람직합니다).