1편에서는...
1편에서는 도메인 모델을 정립하고 (내 나름대로의) 커뮤니케이션 다이어그램을 완성해봤다. 2편에서는 위 다이어그램을 클래스 수준으로 구체화하여 실제 프로그래밍으로 구현하고 클래스 다이어그램을 그려보았다.
다이어그램을 보면 하나의 사이클이 생기는 것을 볼수 있다. 시스템이 플레이전략을 정하면 플레이어는 플레이를 하고 체커에게 점검을 요청한다. 점검을 완료한 체커는 다시 시스템에게 점검결과를 알려준다. 이 일련의 사이클을 하나의 Action이라고 정의하였고, 앞으로도 그렇게 표현하겠다.
턴이라고 정의하지 않은 이유는 한턴에 여러 액션이 일어날 수 있음.
Player → PlayStrategy / Player → Checker : 게임을 하고, 결과를 점검해라
위 그림은 내가 구현한 코드의 클래스 다이어그램이다. (인터페이스의 구현객체는 생략함)
일단 Player는 정해진 Play전략의 PlayStrategy 인터페이스를 생성한다. PlayStrategy 인터페이스는 두가지 책임이 있는데 첫번째는 플레이를 할 책임(보드의 타일을 삽입하거나 삭제함), 두번째는 결과를 점검하는 것이다. 코드로 구현면 다음과 같다.
Player.java
package system;
import play.PlayStrategy;
public class Player {
private String name;
private PlayStrategy playStrategy;
public Player(String name) { this.name = name; }
public String getName() { return this.name; }
public void playTurn() {
this.playStrategy.play();
this.playStrategy.validCheck();
}
public void setPlayStrategy(PlayStrategy playStrategy) {
this.playStrategy = playStrategy;
}
}
setPlayStrategy 메서드를 통해 다음으로 실행될 플레이전략이 결정된다. 이에 따라 playTurn() 메서드를 실행시켜 플레이를 하고 결과를 점검한다.
PlayStrategy.java
package play;
public interface PlayStrategy {
public void play();
public void validCheck();
}
Board.java
package board;
// singleton
public class Board {
private static Board instance = null;
private Board() {}
public static Board getInstance() {
if ( instance == null) {
return new Board();
}
return instance;
}
public void pushTile(int type, int x, int y) {}
public void popTile() {}
}
Board 객체의 경우, 프로그램에 오직 한개만 있으므로 싱글톤 패턴으로 구현하였는데, 또한 Board객체의 경우, 특성 상 여러 객체의 요청을 받아들여 처리하므로 (checker 상속 객체들과 playstrategy의 구현객체들이 모두 사용함) 싱글톤으로 만드는 것이 효율적이라고 생각했다.
Checker → System : 점검결과를 알려주고 Action을 종결해라.
Player 객체의 플레이와 결과점검이 끝나면 점검결과를 System에 전달해 전달결과를 통해 Action을 마무리하고 다음 Action을 정해야 한다. 위 그림은 그과정을 나타낸 클래스 다이어그램이다. ExexcuteChecker는 Play전략에 따라 필요한 점검모듈들을 ChckerFactory를 통해 받는다.
예를들어 'PutTile(타일놓기)' Action에서 플레이를 한 후에는
- 타일을 초과해서 썼는가
- 타일이 타일과 연결되었는가
- 타일을 놓은 위치가 새로운 위치인가
이 3가지 모듈을 통해 점검해야 한다.
점검이 끝나면 이 결과를 규합해 최종 result값을 System.state의 정적 열거타입으로 선언하여 이 값을 인자로 하여 endAction을 호출한다. 그러면 System.state값을 보고 System이 최종 Action을 마무리하고, 다음 Action을 준비한다.
아래는 실제 구현한 코드이다.
ExecuteChecker.java
package checker;
import system.System;
public class ExecuteChecker {
public void execute(String action) {
CheckerFactory checkerFactory = new CheckerFactory();
System.State result = System.State.NONE;
switch(action) {
case "PutTile":
result = checkerFactory.createChecker("OneTileChecker").check();
// detail
break;
case "EndTurn":
result = checkerFactory.createChecker("FullTileChecker").check();
// detail
break;
case "HandleError":
result = checkerFactory.createChecker("OneTileChecker").check();
// detail
break;
// detail
}
System.getInstance().endAction(result);
}
}
아직 디테일한 result값을 구하는 코드는 구현하지 않았다. 일단 전체적인 로직만 보자면 playStrategy에 따라 서로 다른 메세지가 executeChecker에게 전송된다. 그러면 그 메세지를 기반으로 생성해야한 체커 객채를 선택해야 생성후 check()메서드를 실행해 결과값을 구한다. 그리고 그 결과를 System의 endTurn()메서드의 인자로 보낸다.
CheckerFactory.java
package checker;
public class CheckerFactory {
public Checker createChecker(String checker) {
Checker ret = null;
switch (checker) {
case "OneTileConnect":
ret = new OneTileConnect();
break;
case "FullTileConnect":
ret = new FullTileConnect();
break;
case "RestTile":
ret = new RestTile();
break;
// 추가적인 점검 모듈 작성 예정
}
return ret;
}
}
CheckerFactory 객체는 각각의 모듈을 생성하는 역할을 한다. executeCheacker에게 checker 메세지를 받아 생성한다.
Checher.java
package checker;
import system.System;
public abstract class Checker {
public abstract System.State check();
}
System → Player : 플레이 전략을 결정해라
결과를 점검하고 Action을 종료하면 다음 Action을 결정해야 한다. 이를 위해 먼저 endAction 메서드가 실행된다. 이때 필요의 경우 UserInput이 함께 실행되며 이 결과를 통해 beginAction()이 실행된다. beginAction은 다음 플레이 전략을 결정하고 이를 PlayTrigger에게 보내면 PlayTrigger는 Player에게 PlayerStrategy 객체를 생성할 것을 요청한다.
Lock의 경우 Action 수행 중의 유저 인풋을 막는 역할을 한다. endAction 메서드가 userInput이 필요한 경우에만 Lock을 풀어 유저의 입력을 받고, beginAction 메서드가 실행됨에 따라 다시 Lock이 걸린다.
System과 Lock, UserInput(GUI 파트)은 아직 구현중
최종적인 클래스 다이어그램은 다음과 같다.
다음편에는...
System 객체의 구현 / 각 객체및 메서드의 세부구현 / GUI와 내부 프로그램 연결
'프로젝트 이야기 > 지니어스:모노레일' 카테고리의 다른 글
5편 : 싱글턴(Singleton) 없애기 (0) | 2021.12.23 |
---|---|
4편 : GUI 구현 (0) | 2021.12.22 |
3편 : Board 객체 구현하기 (feat. 객체가 갖는 데이터(필드)에 대한 이야기...) (0) | 2021.12.17 |
1편 : 설계하기 (0) | 2021.12.14 |
2년전 자바 텀프로젝트 리팩터링하기 : 들어가며 (0) | 2021.12.09 |