티스토리 뷰

반응형

Head First - Design Patterns 의 템플릿 메소드 패턴 기반으로 작성하였습니다. 자세한 설명은 도서를 참고해주세요.

플라이웨이트 패턴이라고 들어보셨나요? 이미 해당 패턴인지 모르고 사용하는 분들도 많을거 같습니다. 이번 시간은 플라이웨이트 패턴에 대해서 알아보겠습니다.

어떤 클래스의 인스턴스 한 개만 가지고 여러 개의 ‘가상 인스턴스’ 를 제공할 때 플라이웨이트 패턴을 사용하면됩니다. 그럼 바로 UML 을 보면서 어떤 패턴인지 감을 잡겠습니다.

 

예시를 통한 플라이웨이트 알아보기

조경 설계 애플리케이션에서 나무 객체를 추가해야 할 시나리오를 갖고 생각해보겠습니다.

우리는 나무 객체를 랜덤한 x.y 을 받고 객체를 생성할 것입니다. 그렇게 되었을 많은 객체를 생성하게 되면 한달 빠르면 일주일 안에 애플리케이션이 느려지는 것을 확인 할 수 있습니다.
Tree의 인스턴스는 하나만 만들고 나무의 상태를 클라이언트 객체에서 관리하도록 한다면 메모리 절약할 수 있을 것입니다. 이 방식이 플라이웨이트 패턴입니다.

장점
실행시에 객체 인스턴스 객체 개수를 줄여서 메모리 절약할 수 있습니다.
가상 객체를 한 곳에서 확인 할 수 있습니다.

단점
플라이웨이트 패턴으로 적용하면 특정 인스턴스만 다른 행동을 하도록 처리하는 것은 불가능하다는 단점이 있습니다.

class TreeManger {
    companion object {
        private const val MAX_X = 10
        private const val MAX_Y = 10
    }

    // 모든 가상 Tree 객체의 상태가 저장된다.
    // 편의상 Key을 String으로 받았으나 다른 object로 변경해도 됩니다.
    private var treeArray = HashMap<String, Tree>()

    fun displayTrees(count: Int) {
        println("=======================")
        for(i in 0..count){
            createTree()
        }
        println("=======================")
        for(tree in treeArray){
            tree.value.display()
        }
        println("=======================")
    }

    // Tree을 생성하는데 HashMap에 없을 시 존재하고 있는 Tree를 리턴합니다.
    private fun createTree(): Tree? {
        val randomX = Random.nextInt(0, MAX_X)
        val randomY = Random.nextInt(0, MAX_Y)
        val message = "randomX $randomX, randomY : $randomY"
        val position = "${randomX}_$randomY"
        val tree = treeArray[position]
        if (tree == null) {
            treeArray[position] = Tree(randomX, randomY)
            println("존재하고 있는 Tree 리턴!! ($message)")
        } else {
            treeArray[position]
            println("Tree 생성 ($message)")
        }
        return treeArray[position]
    }
}
class Tree(private val x: Int, private val y: Int) {
    fun display(){
       println("x = $x, y = $y")
    }
}
/**
 * 나무 객체를 x,y 랜덤으로 생성 시 메모리 관리할 수 있는 방법은 없을까?
 */
class MainApplication {
    companion object {
        val TAG = MainApplication::class.simpleName

        @JvmStatic fun main(args : Array<String>) {
            TreeManger().displayTrees(100)
        }
    }
}

 

마무리

플라이웨이트 패턴은 어떤 클래스의 인스턴스가 필요하지만 모두 똑같은 방식으로 제어할 수 있는 경우에 유용하게 사용할 수 있습니다. 플라이웨이트를 구현 시 싱글턴으로 구현하여 매니저 클래스를 애플리케이션이 종료될 때까지 유지한다면 보다 효율적으로 메모리 관리 할 수 있습니다.

상황에 맞게 플라이웨이트 패턴을 활용하시면 메모리 측면에서 효과를 볼 것으로 예상됩니다.

반응형

'프로그래밍 > Design Patterns' 카테고리의 다른 글

미디에이터(Mediator) 패턴  (0) 2022.02.08
인터프리터(Interpreter) 패턴  (0) 2022.02.02
역할 사슬(Chain of Responsibility) 패턴  (0) 2022.01.21
빌더(Builder) 패턴  (0) 2022.01.20
브리지(Bridge) 패턴  (0) 2022.01.14
댓글