저는 몇 달 전에 시작한 Java의 작은 UML 편집기 프로젝트에서 작업하고 있습니다. 몇 주 후에 UML 클래스 다이어그램 편집기에 대한 작업 복사본이 있습니다.메멘토 패턴 (및 명령)을 사용하여 복잡한 객체의 상태 저장
하지만 지금은 시퀀스, 상태, 클래스 등 다이어그램의 다른 유형을 지원하기 위해 완전히 다시 디자인하고 있습니다.이 작업은 그래프 구성 프레임 워크를 구현하여 수행됩니다 (저는 Cay Horstmann에서 영감을 얻었습니다). Violet UML 편집기가있는 주제).
내 친구 중 한 명이 프로젝트에 Do/Undo 기능을 추가하는 것을 잊어 버렸다고 말할 때까지 재 설계가 원활하게 진행되고있었습니다. 제 생각에는 이것이 중요합니다.
개체 지향 디자인 과정을 기억하면서, 나는 즉시 메멘토 및 명령 패턴을 생각했습니다.
여기에 있습니다. 두 개의 ArrayLists (하나는 프로젝트에 Elements라고 함)를 저장하고 다른 하나는 Edges (프로젝트에 링크라고 함)를 저장하는 추상 클래스 AbstractDiagram을 가지고 있습니다. 이 다이어그램은 실행 취소/재실 행할 수있는 명령 스택을 유지합니다. 꽤 표준.
효율적인 방법으로 어떻게 이러한 명령을 실행할 수 있습니까? 예를 들어 노드를 이동하려고합니다 (노드는 INode라는 인터페이스 유형이 될 것이고 거기에서 파생 된 구체적인 노드가있을 것입니다 (ClassNode, InterfaceNode, NoteNode 등)).
위치 정보는 노드의 속성으로 유지되므로 노드 자체에서 해당 속성을 수정하면 상태가 변경됩니다. 디스플레이가 새로 고쳐지면 노드가 이동합니다. 이것은 패턴의 메멘토 (Memento) 부분입니다 (나는 생각합니다). 객체가 상태 그 자체라는 차이점이 있습니다.
또한 원래 노드의 복제본을 이동하기 전에 보관하면 이전 버전으로 되돌릴 수 있습니다. 동일한 기술이 노드에 포함 된 정보 (클래스 또는 인터페이스 이름, 메모 노드의 텍스트, 속성 이름 등)에 적용됩니다.
어떻게하면 다이어그램에서 노드를 실행 취소/다시 실행시 클론으로 대체 할 수 있습니까? 다이어그램에서 참조하는 원래 개체 (노드 목록에 있음)를 복제하면 복제본이 다이어그램에서 참조가 아니며 유일한 점은 명령 자체입니다. 나는 다이어그램에서 ID (예를 들어)에 따라 노드를 찾는 메커니즘을 다이어그램에 포함 시키므로 다이어그램에서 노드를 복제본 (또는 그 반대)으로 바꿀 수 있습니까? Memento와 Command 패턴에 따라 달라질 수 있습니까? 링크는 어떻습니까? 그들은 움직일 수 있어야하지만 링크 (그리고 단지 노드를위한 것)를위한 명령을 만들고 싶지 않고 명령 대상의 유형에 따라 올바른 목록 (노드 또는 링크)을 수정할 수 있어야합니다. 를 참조하고 있습니다.
어떻게 진행 하시겠습니까? 요약하면, 명령/유품 패턴에서 오브젝트의 상태를 표현하는 것이 어려워서 다이어그램 목록에 복원 된 원본 오브젝트와 오브젝트 유형 (노드 또는 링크)에 따라 효율적으로 복구 할 수 있습니다.
고맙습니다.
기ume.
피씨 : 내가 분명하지 않으면 말해주세요. 나는 항상 내 메시지를 분명히 할 것입니다.
편집
는 여기에 내가이 질문을 게시하기 전에 구현하기 시작했다, 내 실제 솔루션입니다.
public abstract class AbstractCommand {
public boolean blnComplete;
public void setComplete(boolean complete) {
this.blnComplete = complete;
}
public boolean isComplete() {
return this.blnComplete;
}
public abstract void execute();
public abstract void unexecute();
}
그런 다음, 명령의 각 유형 AbstractCommand의 구체적인 유도를 사용하여 구현됩니다 :
첫째, 나는 다음과 같이 정의 된 AbstractCommand 클래스가 있습니다.
public class MoveCommand extends AbstractCommand {
Moveable movingObject;
Point2D startPos;
Point2D endPos;
public MoveCommand(Point2D start) {
this.startPos = start;
}
public void execute() {
if(this.movingObject != null && this.endPos != null)
this.movingObject.moveTo(this.endPos);
}
public void unexecute() {
if(this.movingObject != null && this.startPos != null)
this.movingObject.moveTo(this.startPos);
}
public void setStart(Point2D start) {
this.startPos = start;
}
public void setEnd(Point2D end) {
this.endPos = end;
}
}
나는 또한 MoveRemoveCommand (에 ... 이동 또는 개체/노드를 제거)이 있습니다
은 그래서 개체를 이동하는 명령을 가지고있다. instanceof 메소드의 ID를 사용하면 다이어그램에서 자체를 제거 할 수 있도록 다이어그램을 실제 노드 나 링크에 전달할 필요가 없습니다 (생각한 나쁜 생각입니다).
AbstractDiagram도; 추가 가능 개체; AddRemoveType 유형입니다.
@SuppressWarnings("unused")
private AddRemoveCommand() {}
public AddRemoveCommand(AbstractDiagram diagram, Addable obj, AddRemoveType type) {
this.diagram = diagram;
this.obj = obj;
this.type = type;
}
public void execute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.addToDiagram(diagram);
break;
case REMOVE:
this.obj.removeFromDiagram(diagram);
break;
}
}
}
public void unexecute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.removeFromDiagram(diagram);
break;
case REMOVE:
this.obj.addToDiagram(diagram);
break;
}
}
}
마지막으로, 노드 또는 링크 (클래스 이름 등)의 정보를 수정하는 데 사용되는 ModificationCommand가 있습니다. 이것은 나중에 MoveCommand와 병합 될 수 있습니다. 이 수업은 현재 비어 있습니다. 아마도 수정 된 객체가 node 또는 edge (instanceof 또는 ID의 특수 표시를 통해)인지 확인하는 메커니즘을 사용하여 ID 객체를 수행 할 것입니다.
이 좋은 솔루션입니다인가?