우아한테크코스

오목 데코레이터 패턴 구현 : [우아한테크코스 5기 AN_베르]

베르_최성훈 2023. 4. 12. 11:35

오목 미션을 진행하면서 렌주룰의 금수를 처음 알게 되었다.

 

렌주룰의 금수 : 먼저 시작하는 흑돌이 무조건 유리하기 때문에 흑목은 3-3, 4-4, 장목 등을 금지한다. 

 

예를 들어 다음과 같은 경우가 3-3 이고 가운데에 흑돌을 놓을 수 없다.

 

3-3, 4-4 는 다른 사람의 코드를 사용했고 장목은 직접 만들어 사용했다.

 

    override fun isForbidden(location: Location) =
        OmokForbiddenRuleAdapter(board, stone).isForbidden(location) ||
            OmokLongForbidden.isForbidden(board, location, stone)

 

그러다보니 위와 같이 코드를 작성했다.

가독성도 떨어지고 확장성이 떨어져서 좋지 못한 구조이다.

 

그래서 적용해본 것은 데코레이터 패턴!

데코레이터 패턴은 객체에 추가적인 기능을 동적으로 더할 수 있도록 하는 패턴이다.

 

즉, 기존 객체를 변경하지 않고 새로운 기능을 추가할 수 있다.

 

이론적으로 자세한 내용을 알고 싶으면 추천!

 

https://en.wikipedia.org/wiki/Decorator_pattern

 

Decorator pattern - Wikipedia

From Wikipedia, the free encyclopedia Design pattern in object-oriented programming In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behav

en.wikipedia.org

 

데코레이터 패턴 적용하기

 

먼저 OmokForbiddenRule (오목 금수 룰) interface를 정의한다.

 

금수룰은 금수인지 확인하고 Boolean 을 반환한다.

interface OmokForbiddenRule {
    fun isForbidden(location: Location): Boolean
}

 

이 인터페이스를 구현하는 클래스 3-3, 4-4, 장목 룰을 정의한다.

 

이때 3-3, 4-4 는 다른 사람의 코드를 사용한 OmokForbiddenUseOtherRule 을 상속받도록 했다.

 

class OmokThreeForbidden(board: Board, currentStone: Stone) : OmokForbiddenRule,
    OmokForbiddenUseOtherRule(board, currentStone) {
     override fun isForbidden(location: Location): Boolean {
        ...
    }
}

class OmokFourForbidden(board: Board, currentStone: Stone) : OmokForbiddenRule,
    OmokForbiddenUseOtherRule(board, currentStone) {
     override fun isForbidden(location: Location): Boolean {
        ...
    }
}

class OmokLongForbidden(private val board: Board, private val stone: Stone) : OmokForbiddenRule {
    override fun isForbidden(location: Location): Boolean {
        ...
    }
}

 

 

 

그런 다음 OmokForbiddenRuleAdapter 를 만든다.

 

AdapterOmokForbiddenRule 를 상속 받는 것이 핵심이다.

 

class OmokForbiddenRuleAdapter(board: Board, private val currentStone: Stone) :
    OmokForbiddenRule { 

    private val forbiddenRulesByStone = mapOf(
        Stone.BLACK to listOf(
            OmokThreeForbidden(board, currentStone),
            OmokFourForbidden(board, currentStone),
            OmokLongForbidden(board, currentStone)
        ),
        Stone.WHITE to listOf()
    )

    override fun isForbidden(location: Location): Boolean {
        return forbiddenRulesByStone[currentStone]?.any{
            it.isForbidden(location)
	}?: false
    }
}

 

stone 을 key, rules 를 value 로 하는 Map을 만든다!

 

rules List 만 업데이트 해주면 쉽게 새로운 금수룰을 변경하거나 삭제할 수 있다!

 

그럴리 없겠지만 혹시나 빨간색 돌이 생긴다면 Map 의 원소를 추가해주면 된다~