1. 디자인 패턴 소개
디자인 패턴은 소프트웨어 엔지니어링에서 반복적으로 발생하는 문제를 해결하기 위해
고안된 일반적인 솔루션을 의미합니다. 이러한 패턴은 개발자들이 더 나은 구조의
소프트웨어를 설계할 수 있도록 도와줍니다. 디자인 패턴은 주로 객체지향 프로그래밍에서
널리 사용되며, 코드를 재사용하고 유지관리할 수 있는 용이성을 제공합니다.
디자인 패턴은 크게 세 가지 유형으로 나눌 수 있습니다: 생성 패턴, 구조 패턴, 행동 패턴.
이번 글에서는 생성 패턴에 대해 자세히 살펴보겠습니다.
2. 생성 패턴
생성 패턴은 객체 생성 관련 문제를 다룹니다. 이 패턴들은 객체 생성 방식을 정의하여
클라이언트 코드와 객체 생성 로직 간의 결합도를 낮춰줍니다. 생성 패턴의 대표적인 예로는
싱글턴(Singleton), 팩토리 메서드(Factory Method), 추상 팩토리(Abstract Factory)
가 있습니다.
3. 싱글턴 패턴
싱글턴 패턴은 클래스의 인스턴스가 오직 하나만 존재하도록 보장하며,
그 인스턴스에 접근할 수 있는 전역적인 접근점을 제공합니다.
이 패턴은 주로 설정, 로그 기록, 데이터베이스 연결 등과 같이
애플리케이션 전역에서 단일 인스턴스가 필요한 경우에 사용됩니다.
3.1. 구현 예제
public class Singleton
{
private static Singleton instance;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
public void SomeBusinessLogic()
{
// 비즈니스 로직
}
}
설명: 위의 구현에서 Singleton 클래스는 private 생성자를 가지고 있어
외부에서 직접 인스턴스를 생성할 수 없습니다. Instance 속성을 통해 싱글턴 객체를
접근할 수 있으며, 인스턴스가 null인 경우에만 새로 생성됩니다.
3.2. 사용 예제
class Program
{
static void Main(string[] args)
{
Singleton singleton = Singleton.Instance;
singleton.SomeBusinessLogic();
}
}
설명: Main 메서드에서는 Singleton.Instance를 호출하여
싱글턴 인스턴스에 접근하고, 비즈니스 로직을 수행합니다.
4. 팩토리 메서드 패턴
팩토리 메서드 패턴은 객체 생성의 인터페이스를 정의하지만,
어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하도록 하는
패턴입니다. 이 패턴은 객체 생성을 캡슐화하여 클라이언트 코드에서
객체 생성에 대한 의존성을 줄여줍니다.
4.1. 구현 예제
public abstract class Creator
{
public abstract Product FactoryMethod();
public void SomeOperation()
{
// 제품 객체를 생성하고 사용함
var product = FactoryMethod();
}
}
public class ConcreteCreatorA : Creator
{
public override Product FactoryMethod()
{
return new ConcreteProductA();
}
}
public class ConcreteCreatorB : Creator
{
public override Product FactoryMethod()
{
return new ConcreteProductB();
}
}
public abstract class Product
{
public abstract string GetInfo();
}
public class ConcreteProductA : Product
{
public override string GetInfo()
{
return "ConcreteProductA";
}
}
public class ConcreteProductB : Product
{
public override string GetInfo()
{
return "ConcreteProductB";
}
}
설명: Creator 추상 클래스는 FactoryMethod() 메서드를 정의합니다.
ConcreteCreatorA와 ConcreteCreatorB는 각각 다른 종류의 Product 객체를 생성합니다.
4.2. 사용 예제
class Program
{
static void Main(string[] args)
{
Creator creator;
// A 타입의 제품 생성
creator = new ConcreteCreatorA();
var productA = creator.FactoryMethod();
Console.WriteLine(productA.GetInfo());
// B 타입의 제품 생성
creator = new ConcreteCreatorB();
var productB = creator.FactoryMethod();
Console.WriteLine(productB.GetInfo());
}
}
설명: Main 메서드에서는 ConcreteCreatorA와 ConcreteCreatorB를 사용하여
서로 다른 타입의 제품을 생성하고 출력합니다.
5. 추상 팩토리 패턴
추상 팩토리 패턴은 관련된 객체들의 집합을 생성하는 인터페이스를 제공합니다.
이 패턴은 클라이언트 코드가 구체적인 클래스에 의존하지 않고,
고수준의 인터페이스를 통해 객체를 생성할 수 있도록 합니다.
주로 관련된 제품군을 만들어야 할 때 유용합니다.
5.1. 구현 예제
public interface IAbstractFactory
{
IProductA CreateProductA();
IProductB CreateProductB();
}
public class ConcreteFactory1 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ProductA1();
}
public IProductB CreateProductB()
{
return new ProductB1();
}
}
public class ConcreteFactory2 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ProductA2();
}
public IProductB CreateProductB()
{
return new ProductB2();
}
}
public interface IProductA
{
string GetProductInfo();
}
public class ProductA1 : IProductA
{
public string GetProductInfo()
{
return "ProductA1";
}
}
public class ProductA2 : IProductA
{
public string GetProductInfo()
{
return "ProductA2";
}
}
public interface IProductB
{
string GetProductInfo();
}
public class ProductB1 : IProductB
{
public string GetProductInfo()
{
return "ProductB1";
}
}
public class ProductB2 : IProductB
{
public string GetProductInfo()
{
return "ProductB2";
}
}
설명: IAbstractFactory 인터페이스는 두 가지 타입의 제품을
생성하는 메서드를 정의합니다. 각 구체적인 팩토리는 이를 구현하여
스스로의 제품을 생성합니다.
5.2. 사용 예제
class Program
{
static void Main(string[] args)
{
IAbstractFactory factory = new ConcreteFactory1();
var productA = factory.CreateProductA();
var productB = factory.CreateProductB();
Console.WriteLine(productA.GetProductInfo());
Console.WriteLine(productB.GetProductInfo());
}
}
설명: Main 메서드에서는 ConcreteFactory1을 통해
ProductA1과 ProductB1 객체를 생성하고 정보를 출력합니다.
디펜던시가 구체적인 제품이 아닌 추상화된 형태로 제공되므로,
변경이 용이해집니다.
6. 결론
이번 글에서는 C#에서 디자인 패턴, 특히 생성 패턴에 대해 알아보았습니다.
싱글턴, 팩토리 메서드, 추상 팩토리 패턴을 통해 객체 생성을 좀 더 유연하고,
재사용 가능한 방법으로 처리할 수 있음을 보여주었습니다. 디자인 패턴을 적절히
활용하면 코드의 가독성과 유지보수성을 높일 수 있습니다. 앞으로도 다양한
디자인 패턴에 대한 이해를 넓히고, 적절히 활용해 보시길 바랍니다.