이제 undo&redo 구현의 핵심인 CommandManager를 설명해보겠다.
src/common/CommandManager.ts
class CommandManager {
public undoList: Command[];
public redoList: Command[];
constructor() {
this.undoList = []
this.redoList = []
}
execute(command: Command) {
command.execute();
this.undoList.push(command);
this.redoList = [];
storeChannel.publish(StoreChannelType.EDIT_TOOLS_CHANNEL, null);
}
undo() {
if (this.undoList.length > 0) {
const command: Command | undefined = this.undoList.pop();
if (command) {
this.redoList.push(command);
command.undo();
storeChannel.publish(StoreChannelType.EDIT_TOOLS_CHANNEL, null);
}
}
}
redo() {
if (this.redoList.length > 0) {
const command: Command | undefined = this.redoList.pop();
if (command) {
this.undoList.push(command);
command.execute();
storeChannel.publish(StoreChannelType.EDIT_TOOLS_CHANNEL, null);
}
}
}
}
undoList와 redoList 변수를 선언한다.
CommandManager Class에 존재하는 함수에 대해 설명하자면
execute(command: Command)
커맨드를 불러와서 실행시킨다. 해당 커맨드가 가지고 있는 execute 함수를 실행시킨다.
그런 뒤 나중의 undo 기능을 실행할때를 대비하여 생성자에 적어뒀던 this.undoList에 커맨드를 저장해 놓는다.
해당 커맨드가 수행이되면 redo의 기능이 초기화되기 때문에 this.redoList를 초기화시킨다.
undo()
undo를 실행할때 undoList에 저장됐던 command를 꺼내어 redoList에 push 해준다.
그런 후 꺼내온 command의 undo 함수를 실행한다.
redo()
redoList에서 command를 꺼내오고 그 command를 undoList에 넣은 다음, command의 execute함수를 실행한다.
공통적으로 각 함수의 마지막에서 state값이 변경됐음을 알리는 publish 함수를 호출한다.
클라이언트 기반 웹 음성 편집기 프로젝트에서 사용된 커맨드 구조는 다음과 같다.
CommandManager
undoList와 redoList를 변수로 두며 execute 함수가 실행될때 해당 command를 undoList에 넣고 command의 execute 함수를 실행한다. 이때 실행한 후엔 redo를 할 수 없기때문에 redoList를 빈 배열로 초기화한다.
undo 함수가 실행될땐 undoList에서 pop을 한 후 해당 command를 redoList에 넣어준다. 그런 후 꺼낸 command의 undo 함수를 실행한다.
redo 함수가 실행될땐 redoList에서 command를 pop한 후 해당 command를 undoList에 넣어준다. 그런 후 꺼낸 command의 execute 함수를 실행한다.
DeleteCommand
해당 파일과 같이 Command가 붙어있으면 command를 나타내는 파일이다.
CommandController
커맨드를 실행시킨다. 예를 들어 client에서 트랙 삭제 기능을 사용하고싶을때 CommandController에 있는 executeDeleteTrackCommand를 호출하여 커맨드를 실행시킬 수 있다.