-
팩토리 패턴(Factory Pattern)CS이론/디자인패턴 2023. 8. 11. 17:10
팩토리 패턴이란?
팩토리 패턴(Factory Pattern)은 GoF의 생성 패턴 중 하나로 객체 생성 부분을 떼어내 추상화한 패턴입니다. 즉, 상속 관계의 클래스에서 상위 클래스는 뼈대를 정하고 하위 클래스는 객체 생성을 결정하는 패턴입니다. 팩토리 패턴은 팩토리 메서드 패턴(Factory Method Pattern)과 추상 팩토리 패턴(Abstract Factory Pattern) 두 가지가 있습니다.
장점
객체 생성 로직이 따로 떨어져 있기 때문에 결합도를 낮출 수 있으며, 유지 보수성이 증가됩니다. 팩토리 패턴은 새로운 Product 추가 시 기존의 코드는 수정하지 않고 새로운 Product만 생성하면 되기 때문에 확장에는 열려있고, 수정에는 닫혀있는 OCP(개방 폐쇄의 원칙)을 따릅니다.
단점
팩토리 패턴의 단점은 패턴을 구현할 많은 서브 클래스가 필요하기 때문에 코드가 복잡해질 수 있습니다.
구현
앞서 팩토리 패턴은 팩토리 메서드 패턴과 추상 팩토리 패턴 두 가지가 있다고 소개했습니다. 두 패턴을 알기 전에 심플 팩토리(Simple Factory)을 먼저 보고 가겠습니다.
- 심플 팩토리(Simple Factory)
심플 팩토리는 팩토리 메서드 패턴과 추상 팩토리 패턴의 베이스가 되는 가장 단순한 형태의 형식으로 엄밀히 따지면 디자인 패턴은 아니라 OOP에서 자주 쓰이는 관용구로 사용됩니다.
interface Coffee { void makeCoffee(); void drink(); } class SimpleCoffeeFactory { public static Coffee orderCoffee(String type) { Coffee coffee = createCoffee(type); coffee.makeCoffee(); return coffee; } private static Coffee createCoffee(String type) { switch(type) { case "Americano": return new Americano(); case "Latte": return new Latte(); default: return new Maxim(); } } } class Maxim implements Coffee { @Override public void makeCoffee() { System.out.println("Make Maxim Coffee"); } @Override public void drink() { System.out.println("Drink Maxim Coffee"); } } class Americano implements Coffee { @Override public void makeCoffee() { System.out.println("Make Americano Coffee"); } @Override public void drink() { System.out.println("Drink Americano Coffee"); } } class Latte implements Coffee { @Override public void makeCoffee() { System.out.println("Make Latte Coffee"); } @Override public void drink() { System.out.println("Drink Latte Coffee"); } } public class SimpleFactory { public static void main(String[] args) { Coffee coffee = SimpleCoffeeFactory.orderCoffee("Americano"); coffee.drink(); coffee = SimpleCoffeeFactory.orderCoffee(""); coffee.drink(); } } /* 출력 결과 Make Americano Coffee Drink Americano Coffee Make Maxim Coffee Drink Maxim Coffee */
코드를 살펴보면 클라이언트가 아닌 SimpleCoffeeFactory에서 createCoffee()를 통해 직접 객체를 생성합니다. 이처럼 심플 팩토리는 단순히 객체를 만드는 작업을 하나의 팩토리 클래스에 모아두는 것을 의미합니다.
- 팩토리 메서드 패턴(Factory Method Pattern)
심플 팩토리를 통해 각 클라이언트에서 구현 클래스에 의존하지 않도록 분리하는 작업을 했습니다. 하지만 새로운 클래스가 추가될 경우 Factory 클래스를 수정해야 한다는 한계가 있습니다. 하지만 기존 코드의 변경 없이 확장이 가능한 패턴이 팩토리 메서드 패턴입니다.
interface Coffee { void createType(); void makeAmericano(); void makeLatte(); } class PressCoffee implements Coffee { @Override public void createType() { System.out.println("Create Press Coffee"); } @Override public void makeAmericano() { System.out.println("Make Americano at PressCoffee"); } @Override public void makeLatte() { System.out.println("Make Latte at PressCoffee"); } } abstract class CoffeeFactory { public Coffee newInstance() { Coffee coffee = createCoffee(); coffee.createType(); return coffee; } abstract Coffee createCoffee(); } class PressCoffeeFactory extends CoffeeFactory { @Override Coffee createCoffee() { return new PressCoffee(); } } public class FactoryMethodPattern { public static void main(String[] args) { CoffeeFactory coffeeFactory = new PressCoffeeFactory(); Coffee coffee = coffeeFactory.newInstance(); coffee.makeAmericano(); } } /* 출력 결과 Create Press Coffee Make Americano at PressCoffee */
// 확장 - 새로운 클래스 추가할 경우 interface Coffee {...} class PressCoffee implements Coffee {...} abstract class CoffeeFactory {...} class PressCoffeeFactory extends CoffeeFactory {...} class DripCoffee implements Coffee { @Override public void createType() { System.out.println("Create Drip Coffee"); } @Override public void makeAmericano() { System.out.println("Make Americano at DripCoffee"); } @Override public void makeLatte() { System.out.println("Make Latte at DripCoffee"); } } class DripCoffeeFactory extends CoffeeFactory { @Override Coffee createCoffee() { return new DripCoffee(); } } public class FactoryMethodPattern { public static void main(String[] args) { CoffeeFactory coffeeFactory = new PressCoffeeFactory(); Coffee coffee = coffeeFactory.newInstance(); coffee.makeAmericano(); // 클라이언트 코드 수정없이 확장하여 사용 CoffeeFactory dripFactory = new DripCoffeeFactory(); Coffee dripCoffee = dripFactory.newInstance(); dripCoffee.makeAmericano(); } } /* 출력 결과 Create Press Coffee Make Americano at PressCoffee Create Drip Coffee Make Americano at DripCoffee */
이처럼 팩토리 메서드 패턴은 객체를 생성할 때 어떤 클래스의 인스턴스를 만들지는 서브 클래스에서 결정하는 패턴입니다. 즉, 인스턴스 생성을 서브 클래스에게 위임합니다. 이 패턴의 장점은 확장할 때 기존 코드의 변경이 없어도 된다는 점이 있습니다. 즉, OCP원칙을 따르는 패턴입니다.
- 추상 팩토리 패턴(Abstract Factory Pattern)
추상 팩토리 패턴은 팩토리 메서드 패턴과 비슷해 보입니다. 하지만 추상 팩토리 패턴은 연관된 객체들을 모아둔다는 차이점이 있습니다. 즉, 구체적인 클래스에 의존하지 않고 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴입니다.
interface Americano {} class DripAmericano implements Americano {} class PressAmericano implements Americano {} interface Latte {} class DripLatte implements Latte {} class PressLatte implements Latte {} interface CoffeeFactory { Americano createAmericano(); Latte createLatte(); } class DripCoffeeFactory implements CoffeeFactory { @Override public Americano createAmericano() { System.out.println("Create Americano at DripCoffee"); return new DripAmericano(); } @Override public Latte createLatte() { System.out.println("Create Latte at DripCoffee"); return new DripLatte(); } } class PressCoffeeFactory implements CoffeeFactory { @Override public Americano createAmericano() { System.out.println("Create Americano at PressCoffee"); return new PressAmericano(); } @Override public Latte createLatte() { System.out.println("Create Latte at PressCoffee"); return new PressLatte(); } } public class AbstractFactoryPattern { public static void main(String[] args) { use(new DripCoffeeFactory()); use(new PressCoffeeFactory()); } private static void use(CoffeeFactory coffeeFactory) { Americano americano = coffeeFactory.createAmericano(); Latte latte = coffeeFactory.createLatte(); } } /* 출력 결과 Create Americano at DripCoffee Create Latte at DripCoffee Create Americano at PressCoffee Create Latte at PressCoffee */
이처럼 Americano와 Latte라는 Product를 Coffee라는 하나의 공통점으로 묶어서 CoffeeFactory를 정의할 수 있었습니다. 팩토리 메서드 패턴과 비슷하지만 공통된 집합을 모아둔다는 특징이 있는데 추상 팩토리 패턴입니다.
참고
Factory 패턴 (1/3) - Simple Factory
'CS이론 > 디자인패턴' 카테고리의 다른 글
싱글톤 패턴(Singleton Pattern) (0) 2023.08.10