코딩으로 학습하는 GoF의 디자인 패턴 (인프런) - 팩토리 메소드 패턴

김민혁·2023년 1월 15일
0
post-thumbnail

이 게시글은 코딩으로 학습하는 GoF의 디자인 패턴 (인프런 - 백기선)
강의를 듣고 정리한 내용을 바탕으로 작성되었습니다.

팩토리 메소드 패턴이란?

팩토리 메소드 패턴은 상위클래스에서 객체 생성을 위한 인터페이스를 제공하여
하위 클래스에게 구체 클래스의 객체 생성을 위임하는 패턴이다.

어떤 문제를 해결하기 위한 패턴인가?

후라이드 치킨을 만드는 치킨가게를 생각해보자 치킨 가게에서는 치킨을 직접 만들고 손님에게 제공한다.


public class FriedChicken {
    private String name;
    private int price;

    public FriedChicken(String name, int price) {
        this.name = name;
        this.price = price;
    }
    
	@Override
    public String toString() {
        return "바삭바삭 후라이드 치킨";
    }
}

.........................


public class ChickenShop {

    private FriedChicken makeFriedChicken() {
        return new FriedChicken("후라이드 치킨",20000);
    }

    public FriedChicken serveChicken() {
        System.out.println("잠시만 기다려 주세요 치킨을 만들어 드리겠습니다.");
        FriedChicken friedChicken = makeFriedChicken();
        System.out.println("치킨이 완성되었습니다 맛있게 드세요 *^ㅡ^*");
        return friedChicken;
    }
}

현재는 후라이드 치킨만 파는 가게다 하지만 장사가 잘 되어서
양념치킨 메뉴를 추가해야한다면 어떻게 될까?

후라이드 치킨과 양념 치킨을 추상화하여 치킨이라는 상위타입을 만들고 손님이 주문한 치킨의 이름에 따라 그에 맞는 치킨을 만드는 방식으로 구현할 수 있다.


public interface Chicken {
}
public class FriedChicken implements Chicken{
    ....

    @Override
    public String toString() {
        return "바삭바삭 후라이드 치킨";
    }
}
public class SeasonedChicken implements Chicken {

    ....

    @Override
    public String toString() {
        return "새콤달콤 양념 치킨";
    }
}
public class ChickenShop {

    private FriedChicken makeFriedChicken() {
        return new FriedChicken("후라이드 치킨", 20000);
    }

    private SeasonedChicken makeSeasonedChicken() {
        return new SeasonedChicken("양념 치킨", 20000);
    }

    public Chicken serveChicken(String chickenName) {
        System.out.println("잠시만 기다려 주세요 치킨을 만들어 드리겠습니다.");
        Chicken chicken;
        if ("후라이드 치킨".equals(chickenName)) {
            chicken = makeFriedChicken();
        } else if ("양념 치킨".equals(chickenName)) {
            chicken = makeSeasonedChicken();
        } else {
            throw new IllegalArgumentException("그런 치킨은 없는뎁숑");
        }
        System.out.println("치킨이 완성되었습니다 맛있게 드세요 *^ㅡ^*");
        return chicken;
    }
}

성공적으로 양념치킨을 팔 수 있게 되었지만 이러한 구조라면 이 치킨집은 치킨 메뉴가 추가될때마다 장사방식(코드)을 수정해야한다. 또 치킨의 레시피가 바뀐다고 해도 마찬가지이다. 결합도가 매우 높은 것이다!! 이러한 문제점을 객체지향적으로 잘 해결하기위해서 팩토리 메소드 패턴을 사용할 수 있다.

팩토리 메소드 패턴 구현

public interface ChickenShop {

    default Chicken serveChicken() {
        System.out.println("잠시만 기다려 주세요 치킨을 만들어 드리겠습니다.");
        Chicken chicken = makeChicken();
        System.out.println("치킨이 완성되었습니다 맛있게 드세요 *^ㅡ^*");
        return chicken;
    }

    Chicken makeChicken();
}
public class FriedChickenFactory implements ChickenShop{

    @Override
    public Chicken makeChicken() {
        return new FriedChicken("후라이드 치킨", 20000);
    }
}
public class SeasonedChickenFactory implements ChickenShop{

    @Override
    public Chicken makeChicken() {
        return new SeasonedChicken("양념 치킨", 20000);
    }
}

다음과 같은 방식으로 팩토리 메소드 패턴을 구현할 수 있다.

ChickenShop에서 추상메소드 makeChicken()를 통해 하위 클래스인 FriedChickenFactory SeasonedChickenFactory 에게 구체적인 객체(후라이드치킨, 양념 치킨)의 생성을 위임하였다.

이제 치킨 메뉴가 추가되면 Chicken을 구현하는 다른 치킨 클래스를 추가하고 ChickenShop 을 구현하는 다른 치킨 팩토리를 구현하기만 하면 된다.

기존 클래스의 변경없이 확장을 통해 기능을 추가할 수 있게 되었다. 즉 OCP - 개방 폐쇄 원칙를 만족하는 구조를 완성한 것이다!

주문을 해보자

public class Customer {
    private Chicken orderChicken(ChickenShop chickenShop) {
        return chickenShop.serveChicken();
    }

    private void eatChicken(Chicken chicken) {
        System.out.println("냠냠 맛있는 "+chicken);
    }

    public void eatFriedChicken() {
        Chicken chicken = orderChicken(new FriedChickenFactory());
        eatChicken(chicken);
    }

    public void eatSeasonedChicken() {
        Chicken chicken = orderChicken(new SeasonedChickenFactory());
        eatChicken(chicken);
    }

    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.eatFriedChicken();
        System.out.println("===================================");
        customer.eatSeasonedChicken();
    }
}
  • main 실행 결과
profile
안녕하세요 김민혁입니다.

0개의 댓글