팩토리 메서드 패턴
어떤 클래스에 대한 인스턴스를 생성할 때 그에 대한 책임과 권한을 서브클래스에게 위임하는 패턴이다. 클라이언트에서 직접 new 키워드를 사용하여 생성하는 것이 아닌 객체 생성 전용 팩토리 클래스를 호출하고, 어떤 객체를 만들지 결정하는 서브 팩토리 클래스를 통해 객체를 생성한다.
구조
- Product - 팩토리 메서드가 생성하는 객체의 인터페이스.
- ConcreteProduct - Product 클래스에 정의된 인터페이스를 실제로 구현한 서브클래스.
- Creater - Product 타입의 객체를 반환하는 팩토리의 인터페이스. Product 객체의 생성을 위해 호출한다.
- ConcreteCreater - ConcreteProduct 객체를 생성하는 코드의 구체적인 구현이 되어있는 서브클래스.
기본 인터페이스
//팩토리 인터페이스
public interface IFactory
{
public Unit CreateUnit();
}
//팩토리 서브클래스 구현
public class ProductAFactory : IFactory
{
public Unit CreateUnit()
{
return new ProductA();
}
}
//팩토리 서브클래스 구현
public class ProductBFactory : IFactory
{
public Unit CreateUnit()
{
return new ProductB();
}
}
//Product 인터페이스
public interface Unit
{
public void Attack();
public void Move();
}
// Product 서브클래스 구현
public class ProductA : Unit
{
public void Attack(){ Console.WriteLine("A 공격!");}
public void Move(){}
}
// Product 서브클래스 구현
public class ProductB : Unit
{
public void Attack(){Console.WriteLine("B 공격!");}
public void Move(){}
}
public class MainTest
{
public static int Main(string[] args)
{
IFactory factory = new ProductAFactory();
Unit productA = factory.CreateUnit();
factory = new ProductBFactory();
Unit productB = factory.CreateUnit();
productA.Attack();
productB.Attack();
return 0;
}
}
A 공격!
B 공격!
왜 사용해야 할까?
팩토리 메서드를 사용하지 않고 바로 클라이언트가 구현 클래스인 Product를 생성하면 어떻게 될까?
Unit productA = new ProductA();
Unit productB = new ProductB();
코드를 구현할 때는 별 문제가 없을 거라고 생각한다. 하지만 이후 ProductA의 코드가 수정된다면? 객체 ProductA가 ProductA_advanced로 변경된다면 여태까지 구현한 코드들은 어떻게 될까? 모든 코드들에서 ProductA로 생성한 코드들을 ProductA_advanced로 변경해야하는 사태가 벌어질 것이다.
Unit productA = new ProductA();//Error!
Unit productB = new ProductB();
Unit productA = new ProductA_advanced(); // 하나하나 일일이 수정해줘야 한다.
하지만 팩토리를 사용한다면 클라이언트 코드를 수정할 필요가 없다. 그저 팩토리에서 ProductA를 반환하던 코드를 ProductA_advanced로 변경하면 그만이다.
public interface IFactory
{
public Unit CreateUnit();
}
public class ProductAFactory : IFactory
{
public Unit CreateUnit()
{
return new ProductA_advanced();
}
}
IFactory factory = new ProductAFactory();
Unit productA = factory.CreateUnit(); //팩토리에서 생성할 객체를 변경했을 뿐이기에 수정할 코드가 최소화된다.
장점
- 객체 생성에 필요한 코드들을 클래스화함으로써 코드 재사용성을 향상시킨다.
- 객체의 유형과 종속성을 캡슐화 함으로써 느슨한 결합을 이룸 - 수정이 발생하더라도 클라이언트 코드에 최소한의 영향을 끼침
- 기존의 코드를 수정하지 않고 새로운 서브클래스를 생성하여 기능을 확장할 수 있다.(OCP)
- 구체적인 타입에 의존하지 않고 추상에 의존한다.(DIP)
단점
- 다수의 클래스를 생성해야 한다.
추가 예시
심플 팩토리
심플 팩토리는 말 그대로 간단한 팩토리다. 객체를 생성하는 클래스를 따로 둬 느슨한 결합을 이루는 것에만 집중한 패턴이라 할 수 있다. 간단하게 구현이 가능하고 생성할 클래스 수가 적어지지만 OCP와 DIP를 위배한다.
public class SimpleFactory
{
public Unit CreateProduct(string name)
{
//매개변수의 값에 따라 생성하는 객체를 변경
//객체들의 상태에 변화가 발생하면 코드를 변경해야 한다.
if (name.Equals("ProductA"))
{
return new ProductA();
}
else if (name.Equals("ProductB"))
{
return new ProductB();
}
return null;
}
public static int Main(string[] args)
{
SimpleFactory factory = new SimpleFactory();
Unit productA = factory.CreateProduct("ProductA");
Unit productB = factory.CreateUnit("ProductB");
return 0;
}
}
참고자료
GoF의 디자인 패턴 - 예스24
이 책은 디자인 패턴을 다룬 이론서로 디자인 패턴의 기초적이고 전반적인 내용을 학습할 수 있다.
www.yes24.com
'프로그래밍 이론 > 디자인 패턴' 카테고리의 다른 글
05. [Design Pattern] 싱글톤(Singleton) 패턴 (0) | 2023.11.16 |
---|---|
04. [Design Pattern] 프로토타입(Prototype) 패턴 (0) | 2023.11.07 |
03. [Design Pattern] 빌더(Builder) 패턴 (0) | 2023.11.07 |
02. [Design Pattern] 추상 팩토리(Abstract Factory) 패턴 (0) | 2023.10.27 |
00. [Design Pattern] 디자인 패턴이란? (0) | 2023.10.25 |