CS/디자인패턴

팩토리(Factory) 패턴

rkrkrr0101 2024. 7. 14. 21:15

팩토리패턴은 객체의 생성을 대행해주는 패턴들을 통틀어서 말함

 

직접적으로 코드내에서 객체를 생성할경우엔 해당 객체에 강의존될수밖에 없지만,

이 생성부분을 외부로 빼내고 해당클래스를 사용해서 생성해달라고 요청한다음,

인터페이스를 사용해서 받으면 약의존으로 바뀌게됨

 

즉 이걸 사용하면 ocp를 지킬수있는 도구가 됨,

객체의 생성선택권한을 팩토리쪽으로 넘겨주면서 캡슐화해서 변경에 닫혀있게 만드는것

이게 심플 팩토리 패턴임

 

여기서 팩토리를 static으로(코틀린에서는 companion object)로 하면 정적 팩토리 패턴이 되고,

이건 팩토리인스턴스를 만들지않아도 객체들을 생성할수있게되지만

서브클래스로 객체생성메서드를 변경할수없다는 단점이 생겨서 간단한거에 이렇게사용함

 

심플팩토리 패턴은,사용클래스를 추상클래스(인터페이스로 만든다음 전부 구현하고,

팩토리클래스 대신 추상메서드를 사용해 팩토리를 구현하는 방식임

즉 각 클래스마다 공통부분은 그대로 가져가면서,팩토리부분만 직접 구현하라고 하는방식

즉 어떤 구현클래스(서브클래스)를 선택했냐에 따라서 종류를 바꿀수있고,이렇게 확장에는 열려있고 변경에는 닫혀있게 만드는 방식이 심플팩토리 패턴임

 

팩토리메서드 패턴은

서브클래스에서 어떤 클래스를 만들지 결정함으로써 객체생성을 캡슐화함,즉 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하고,객체를 생성할때 필요한 인터페이스만 정의하는 패턴

즉 사용자는 실제 생산될 제품을 전혀 모르는상태로 만들어짐(매개변수넣으면 공통인터페이스로 알아서출력되니)

즉 필요한 매개변수들을 넣고 메서드를 호출하면,해당 메서드에서 알아서 뭘 생성할지 결정한다음 리턴해줌

 

심플팩토리패턴과 팩토리메서드패턴은 많이 비슷한데,차이점은 심플보단 팩터리메서드가 재사용이 용이함

심플팩토리가 캡슐화만 했다면,팩토리메서드는 여기서 매개변수를 추가해서 생성제품을 해당 서브클래스가 변경할수있게 해줌 

 

예를 들면

class ExFactory {
    fun pizza():Pizza{
        return CheesePizza()
    }
}

이게 심플팩토리고

class ExFactory {
    fun pizza(component: String): Pizza {
        when (component) {
            "cheese"->return CheesePizza()
            "tomato"->return TomatoPizza()
            else->throw IllegalArgumentException("unknown component")
        }
    }
}

이게 팩토리메서드임,생성을 해당메서드에 선택할수있게해줌

 

추상팩토리는 모든 공통적인 필드들을 각각 추상화시켜서 인터페이스들의 집합으로 만든다음,각 팩토리마다 해당 필드들의 조합을 리턴해주는 방식임,이러면 각 클래스를 각각 전부 만들필요가 없어짐(그냥 필드가 다른 같은클래스)

이때 팩토리도 추상화된 팩토리를 의존하고,팩토리는 di받으니까 구현팩토리를 해당클래스가 신경쓸필요 없어 

그래서 클래스의 재사용성이 올라감

즉 추상팩토리 패턴은

구상클래스에 의존하지않고 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공하는 패턴

추상팩토리임

이건

fun main(){
    val pizza = Pizza(BananaFactory())
    pizza.cut()
}


class Pizza(factory:InterFactory){
    private val source:Source=factory.createSource()
    private val bread:Bread=factory.createBread()
    
    fun cut(){
        ...
    }
}

class BananaFactory:InterFactory {
    override fun createSource(): Source {
        return BananaSource()
    }
    override fun createBread(): Bread {
        return BananaBread()
    }

}

이런식으로 클래스가 인터페이스 팩토리에 의존하고,팩토리를 di받으면서 사용자쪽에서 알아서 조합해서쓰라고 책임을 넘기는방식의 패턴임

여기서 bananaFactory 말고 chocoFactory같은거도 그냥 InterFactory를 확장해서 만든다음,사용할때 그걸 끼워서 쓰면됨

 

추상팩토리는 그냥 팩토리를 추상화 시킨거니까,여기다가 팩토리메서드로 구현하는방식도 종종 사용됨

어짜피 추상팩토리는 클래스를 만들때 쓰이는 인터페이스를 정의한거일뿐이고,구현을 어케할지는 자기맘이니까

 

또한 추상팩토리는 합성으로 객체를 생성하고,팩토리메서드는 상속으로 객체를 생성함

보통 한 객체안에 채워야할게 많으면 추상팩토리를 사용하게되고,생성해야할 객체종류가 많으면 팩토리메서드를 사용하게됨,둘다면 같이써야하고

  • 클라이언트에서 서로 연관된 일련의 제품을 만들어야하면 추상팩토리
  • 클라이언트 코드와 구상클래스를 분리시켜야하거나,어떤 구상클래스가 필요한지 알수없을땐 팩토리메서드

를 사용하면됨

 

팩토리의 장점은,객체생성코드를 한곳에서 관리할수있게 해주고,중복을 제거해줌

또한 객체인스턴스를 만들때 인터페이스에만 신경써서 만들면됨(뭐가나오든 상관없이),그래서 유연성과 확장성이 올라감

팩토리패턴들은 의존성역전원칙(dip)을,즉 상위요소가 하위요소에 영향을 받지않고 인터페이스에만 의존할수있게 하는데 도움을 주는 패턴임