본문 바로가기

Software Development/디자인 패턴

[디자인 패턴의 정석] 생성패턴 - 팩토리 메서드 패턴 (Factory Method)

팩토리 메서드 패턴의 Class Diagram.

 

개발자 yeah Developer Story - 디자인 패턴

 

오늘은 저번 포스팅에 이어서 팩토리 패턴의 확장 패턴인 팩토리 메서드 패턴을 이야기해보려 합니다.

 

팩토리 메서드 패턴추상화 기법을 사용하여 패턴을 확장하므로, 쉽게 이해하기 위해서는 객체지향의 추상화 개념이 필수입니다!

 

따라서 추상화, 다형성, 상속 에 대한 이해가 부족하시다면 선행 공부를 꼭 하시고 해당 포스팅을 보시길 바래요 ^^

 

 

먼저 팩토리 패턴에서 활용했던 객체들의 관계를 먼저 설명하겠습니다.

 

/* 마피아 게임에서 사용자를 나타내는 class */
abstract class User {
    String name;    //사용자 이름
    String skill;   //스킬

    User(String name) { this.name = name; }
    
    String getName() { return name; }
    
    String getSkill() { return skill; }
}

 

/* 마피아 게임에서 시민을 나타내는 class */
public class Citizen extends User{
    Citizen(String name) {
        super(name);
        setSkill();
    }
    
    void setSkill() {
        this.skill = "투표를 행사할수있음";
    }
}

 

/* 마피아 게임에서 마피아를 나타내는 class */
public class Mafia extends User {
    Mafia(String name) {
        super(name);
        setSkill();
    }
    
    void setSkill() {
        this.skill = "시민을 죽일수있음";
    }
}

 

/* 마피아 게임에서 경찰을 나타내는 class */
public class Police extends User {
    Police(String name) {
        super(name);
        setSkill();
    }
    
    void setSkill() {
        this.skill = "마피아를 찾을수있음";
    }
}

 

User(사용자)라는 추상 클래스가 있고 이를 상속받는 Mafia(마피아), Police(경찰), Citizen(시민) 클래스가 있습니다.

 


기존 팩토리 패턴에서는 객체 생성의 위임을 통해 조건에 따른 객체를 생성 할 수 있도록 Factory를 구현하였습니다.

 

그에 따라 main에서 new 키워드를 통한 객체 생성이 아니기 때문에 강력한 결합을 해결할 수 있었죠.

(main 내에서 다른 객체와 강력한 결합의 해결을 의미)

 

하지만 Factory는 내부적으로는 여전히 객체 생성을 하는 데 있어 강력한 결합을 유지하고 있습니다.

(Factory 내에서 new 키워드를 사용하기 때문에 다른 객체와 강력한 결합이 발생)

 

/* 객체 생성의 위임을 위한 Factory class */
abstract class Factory {
    /* 기존 팩토리 패턴 */
    public User create(String name, String job) {
        switch (job) {
            case "마피아":
                return new Mafia(name);
            case "경찰":/               
            	return new Police(name);
            default:    //시민
                return new Citizen(name);
        }
    }
}

 

main에서 Factory 와 같은 불가피하게 생성해야 될 객체는 유지보수를 위해 최대한 수정이 적게 발생되도록 설계해야 합니다.

 

이 말은 즉 main에서 생성되는 객체는 다른 객체와의 느슨한 결합으로 작성 된 객체들이 생성돼야 유리하다는 의미이죠.

 

하지만 현재의 Factory 는 다른 객체와의 강력한 결합을 통해 구현되어있기 때문에,

 

결합된 객체생성 조건이 수정되거나  확장Factory 내부가 수정될 가능성이 높습니다.

 

이에 따라 main에서 Factory 를 통해 호출되는 코드 부분의 수정이 일어나는 문제점이 생길 수도 있는 거죠.

 


/* 객체 생성의 위임을 위한 Factory class */
abstract class Factory {
    /* 추상화를 결합한 팩토리 메서드 패턴 */
    public final User create(String name, String job) {
        //하위 클래스로 위임
        return this.createUser(name, job);
    }

    abstract public User createUser(String name, String job);
}

 

따라서 기존 Factory 클래스를 추상 클래스로 적용을 하여 객체를 생산하고 사용하는 것을 분리시킴으로써,

 

Factory 클래스를 강력한 결합 형태에서 느슨한 결합 형태로 수정하고 Factory 가 최대한 변경되지 않도록 설계하였습니다.

 

위 코드를 보시면 추상 메서드 createUser()를 통해 하위 클래스에서 객체를 생산하도록 위임하고 create()를 통해 하위클래스임한 함수를 실행 하도록 수정하였습니다.

 

따라서 객체를 생성하기 위해서는 추상 클래스(Factory) 를 상속받은 하위클래스를 만들어 실제적인 추상 메서드의 구현부를 작성해야 합니다.

 

※ 참고로 추상 클래스에서는 실제적인 동작(createUser)을 하위 클래스에 위임함으로써 추상 클래스 안에서 미리 위임된 메서드(createUser)를 사용할 수 있습니다. 

 

 

/* Factory(추상클래스)를 상속받아 실제 구현부를 담당하는 FactoryUser class */
public class FactoryUser extends Factory {
    @Override
    public User createUser(String name, String job) {
        switch (job) {
            case "마피아":
                return new Mafia(name);
            case "경찰":
                return new Police(name);
            default:    //시민
                return new Citizen(name);
        }
    }
}

 

다음은 Factory(추상클래스) 를 상속받아 실제적인 추상메서드를 구현해야 하는 FactoryUser(하위클래스) 입니다.

 

기존 팩토리 패턴조건을 그대로 사용하여 User객체 생성에 대한 구현부를 작성하였습니다.

 

이로써 객체를 생성하는 조건의 수정이 발생하거나 추가 되었을때 FactoryUser(하위클래스) 의 코드만 수정하면 되고,

 

기존 Factory는 수정 할 필요가 없게 되며, main에서 사용되는 Factory 관련 코드도 수정없이 유지 할 수 있습니다.

 


public class FactoryMethodPattern {

    /* 마피아 게임 */
    public static void main(String[] args) {
        Factory factory = new FactoryUser();
        User user1 = factory.create("성민", "마피아");
        User user2 = factory.create("영성", "경찰");
        User user3 = factory.create("승주", "시민");
        User user4 = factory.create("수지", "시민");

        System.out.println("이름 :  " + user1.getName() + ",  스킬 : " + user1.getSkill());
        System.out.println("이름 :  " + user2.getName() + ",  스킬 : " + user2.getSkill());
        System.out.println("이름 :  " + user3.getName() + ",  스킬 : " + user3.getSkill());
        System.out.println("이름 :  " + user4.getName() + ",  스킬 : " + user4.getSkill());
    }
}

 

마지막으로 팩토리 메서드 패턴main() 입니다.

 

위에서 설명했듯이 factory(상위 클래스)실제 구현부를 작성한 하위 클래스(FactoryUser)를 연결하여,

 

factory(상위 클래스) 의 create ()를 통해 객체를 생성하는 것을 볼 수 있습니다. (하위클래스의 구현부를 알 필요가 없음)

 

 

 

이렇게 오늘은 팩토리 패턴에서 추상화 를 결합 한 팩토리 메서드 패턴을 이야기해봤는데요.

 

다음 포스팅으로는 해당 팩토리 메서드 패턴을 확장한 추상 팩토리 패턴을 소개하도록 하겠습니다.

 

감사합니다!