본문 바로가기

Software Development/디자인 패턴

[디자인 패턴의 정석] 생성패턴 - 추상 팩토리 패턴 (Abstract Factory)

추상 팩토리 패턴의 Class Diagram

 

 

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

 

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

 

 

먼저 추상 클래스를 상속받은 하위 클래스의 특징을 설명하도록 하겠습니다.

 

추상클래스에서 정의한 추상 메서드 를 이용하여 각각의 하위 클래스는 이를 오버라이드 하여 목적에 맞도록 실제 동작하는 메서드를 구현 하게 됩니다.

 

만약 목적에 따라 다른 하위클래스가 필요하게 된다면,  그 목적에 따라 실제 동작하는 메서드는 저 마다 다르게 구현 할 수 있습니다.

 

이를 객체지향에서 다형성 이라고 부릅니다.

 


추상화Factory 클래스를 통한 객체 생성은  2가지 방법이 존재하게 되는데요.

 

첫 번째는 지난 포스팅에서 배운 팩토리 메서드 패턴 입니다.

 

팩토리 메서드 패턴 추상화를 통하여 하위 클래스에게 구현을 위임하였으며, 1개의 하위 클래스 안에서 매개변수를 통하여 조건에 따라 각각의 객체 생성을 하였습니다.

 

즉  다형성 을 배제한 방법인 것이죠.

 

 

두 번째는 위에서 언급한 다형성을 적극적으로 이용한 추상 팩토리 패턴 입니다.

 

추상 팩토리 패턴 은 생성해야 될 각각의 객체마다 하위 클래스(Factory) 를 생성하여,  원하는 하위 클래스(Factory) 를 결합하도록 하는 방식입니다.

 

복수의 하위 클래스(Factory) 를 갖는 구조인 것이죠.

 

 

팩토리 vs 팩토리 메서드 vs 추상 팩토리 비교.


 

자 그럼 이제 코드를 살펴보도록 하겠습니다.

 

먼저 기존 팩토리 메소드 패턴 에서 활용했던 객체들을 그대로 사용하여 설명하겠습니다.

 

/* 마피아 게임에서 사용자를 나타내는 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);
        System.out.println(name + " 님은 시민으로 생성 되었습니다.");
        setSkill();
    }
    
    void setSkill() {
        this.skill = "투표를 행사 할 수 있음.";
        System.out.println(name + " 님은 시민 스킬을 장착하였습니다.\n");
    }
}

 

/* 마피아 게임에서 마피아를 나타내는 class */
public class Mafia extends User {
    Mafia(String name) {
        super(name);
        System.out.println(name + " 님은 마피아로 생성 되었습니다.");
        setSkill();
    }
    
    void setSkill() {
        this.skill = "시민을 죽일 수 있음.";
        System.out.println(name + " 님은 마피아 스킬을 장착하였습니다.\n");
    }
}

 

/* 마피아 게임에서 경찰을 나타내는 class */
public class Police extends User {
    Police(String name) {
        super(name);
        System.out.println(name + " 님은 경찰로 생성 되었습니다.");
        setSkill();
    }
    
    void setSkill() {
        this.skill = "마피아를 찾을 수 있음.";
        System.out.println(name + " 님은 경찰 스킬을 장착하였습니다.\n");
    }
}

 

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

 


기존 팩토리 메서드 패턴 에서 정의한 추상클래스를 수정없이 그대로 사용하겠습니다.

 

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

    abstract public User createUser(String name);
}

 

위 코드를 보시면 추상클래스에서 정의한  추상 메서드 createUser()를 통해 하위 클래스에 구현부를 위임하고,

 

create()를 통해 하위클래스에 임한 함수를 실행하도록 설계되어 있습니다.

 

이에 따라 해당 Factory 를 상속받는 하위 클래스들은 저 마다 특징에 맞도록 구현부를 다르게 작성 할 수 있습니다. (다형성)

 

 

다음은 Factory를 상속받을 각각의 하위 클래스 입니다.

 

/* Citizen 객체 생성을 담당할 하위 Factory */
public class CitizenFactory extends Factory {

    @Override
    public User createUser(String name) {
        return new Citizen(name); //Citizen 객체를 생성.
    }
}

 

/* Mafia 객체 생성을 담당할 하위 Factory */
public class MafiaFactory extends Factory {
    @Override
    public User createUser(String name) {
        return new Mafia(name); //Mafia 객체를 생성.
    }
}

 

/* Police 객체 생성을 담당할 하위 Factory */
public class PoliceFactory extends Factory {
    @Override
    public User createUser(String name) {
        return new Police(name); //Police 객체를 생성.
    }
}

 

기존 팩토리 메서드 패턴 과 달리 각각의 하위클래스에서 목적에 해당되는 객체를 생성하는 것을 볼 수 있습니다.

 


다음은 main() 에서 어떻게 처리되는지 확인하도록 하겠습니다.

 

public class AbstractFactoryPattern {

    /* 마피아 게임 */
    public static void main(String[] args) {
        Factory factory = new MafiaFactory();
        User user1 = factory.create("성민");

        factory = new PoliceFactory();
        User user2 = factory.create("영성");

        factory = new CitizenFactory();
        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());
    }
}

 

이전 팩토리 메서드 패턴 에서는 하나의 하위 클래스를 통하여 create() 했지만,

 

추상 팩토리 패턴 에서는 각각의 객체 생성을 담당하는 하위 Factory 를 결합하여 create()를 호출하는 것을 확인할 수 있습니다.

 

 

다음은 main() 의 결과 창입니다.

 

결과 창


팩토리 메서드 패턴  VS  추상 팩토리 패턴

 

 

추상 팩토리 패턴팩토리 메서드 패턴확장이라고 볼 수 있지만, 더 좋은 패턴이라고는 단정 지을 수는 없습니다.

 

추상 팩토리 패턴 동일한 처리로직하위클래스의 결합을 통해 선택적으로 객체를 생성 할 수 있는 장점이 있지만,

 

새로운 객체가 추가된다면 하위 클래스도 같이 추가돼야 하고 확장 시 모든 하위클래스의 수정이 필요 할 수도 있습니다.

 

 

 

팩토리 메서드 패턴   1개의 하위클래스 내 매개변수 를 통해 생성을 선택적으로 처리하기에 다형성의 단점은 해결할 수 있지만,

 

새로운 객체가 추가된다면  조건이 추가 되어야 하고 확장 시 하위클래스의 덩치가 커지기 때문에 유지보수가 어려울수 있습니다.

 

 

따라서 본인이 진행하고 있는 프로젝트의 규모와 설계에 따라 적절한 패턴을 사용하는 것이 좋습니다!

 

 

 

 

이렇게 오늘은 팩토리 메서드 패턴 을 확장한 추상 팩토리 패턴 을 이야기 해봤는데요.

 

궁금하시거나 질문이 있으시면 댓글로 달아주세요 !!

 

감사합니다!