본문 바로가기

Programinng/Design Pattern

자바(Java) - Factory Pattern 팩토리 패턴

Object를 생성할때 new라는 키워드를 쓰는것은 좋지 못하다. 이는 interface가 아니라 Concrete class를 의존하여 코딩을 하기 때문에 결합도가 매우 높다. 그렇기 때문에 나중에 코드를 수정해야 할 가능성이 높아지고, 유연성이 떨어진다. 이를 Factory Pattern을 사용하여 결합도를 느슨하게 만들 필요가 있다. Factory는 공장이라는 뜻으로 Object를 생성하는 공장이다. 실제 사용하는 곳에서 Concrete class를 정하지 않고 Factory를 사용하여 의존성을 받기 때문에  Concrete class를 전혀 의존하지 않는다. 우리는 이런 Factory를 통해 DIP(Dependency Inversion Principle, 의존성 뒤집기 원칙)을 실현 시킬 수 있다. 




자동차를 조립해서 생산하는 프로그램을 생각해보자. 자동차를 생산하는데 필요한 A회사의 엔진을 new를 통해 생산했다면, 엔진 회사를 B로 바꾸라는 요구사항의 변경이 있을때 이는 new를 통해 생성한 모든 자동차 class에서 수정을 해야된다. 하지만 Factory를 통해서 생성 했다면, 이 Factory 메소드만 수정하면 된다. 이는 실제 엔진을 사용하는 class에서는 어떤 엔진이 오던간에 신경쓰지 않아도 되고, Factory에 엔진을 요구하면 알아서 주기 때문에 느슨한 결합도를 유지할 수 있다. (이게 바로 interface를 위주로 코딩을 하여 다형성을 사용할 수 있기 때문에 가능한 일이다.)


public class EngineFactory { 
    public Engine getEngine(String type){ 
        Engine engine = null
        if(type.equals("BMW5 series")){ 

            engine = new AEngine();  
        }else if(type.equals("BMW7 series")){ 

            engine = new BEngine();  
        } 
        return engine; 
    } 
}


이렇게 BMW5 시리즈로 요구사항이 온다면 AEngine을 7시리즈로 온다면 BEngine를 생성해서 주면 된다. 그렇게 되면 이를 사용하는 입장에서는 어떤 엔진이 어떻게 생성되어 오는지 구체적으로 알 필요없이 사용할 수 있다.


사실 이것도 문제가 있다. if문이 있다는 것은 추후에 type이 많아지면 더 많은 조건문이 생긴다는 걸 의미하고 Factory class에서도 그 만큼 수정이 가해 진다는 것을 뜻한다. 이는 properties같은 설정 파일에 class들을 Full Qualified Name까지 저장해 놓고 실행중에 불러와서 Map에 저장해놓고 동적으로 Class.forName("").newInstance()를 통해 객체를 생성하여 반환하는 방법으로 해결 할 수 있다. 


이렇게 함으로써 이제 완성된 코드는 다시 '수정' 해야 할 일을 줄일 수 있고, 변경 되거나 추가되는 사항이 있다면 새로운 class를 정의하고 설정파일만 수정하면 된다. 이렇게 하여 더 이상 완성된 코드를 수정하고 재컴파일 하고 다시 빌드하는 일을 줄일 수 있다.