반응형
전략 패턴
전략 패턴이란?
- 전략 패턴은 알고리즘 군을 정의하고, 각 알고리즘을 캡슐화하며, 이들을 상호 교환 가능하게 만드는 패턴
- 이를 통해 클라이언트는 알고리즘을 독립적으로 변경할 수 있다.
- 알고리즘을 사용하는 클라이언트 코드와 알고리즘 자체를 분리하여, 클라이언트 코드의 변경 없이 알고리즘을 쉽게 변경할 수 있도록 한다.
구조
- Context: 전략을 사용하는 클래스. 클라이언트는 Context를 통해 알고리즘을 실행
- Strategy: 알고리즘을 정의하는 인터페이스
- ConcreteStrategy: 구체적인 알고리즘을 구현하는 클래스
전략 패턴의 중요성
- 유연성: 알고리즘을 동적으로 선택하고 변경할 수 있어, 유연한 설계가 가능하다. 이는 다양한 요구사항을 쉽게 수용할 수 있게 한다.
- 확장성: 새로운 알고리즘을 추가할 때 기존 코드를 수정할 필요 없이, 새로운 ConcreteStrategy 클래스를 추가하기만 하면 된다.
- 유지보수성: 알고리즘을 캡슐화하여, 알고리즘의 구현을 독립적으로 수정할 수 있다. 이는 코드의 유지보수성을 높인다.
전략 패턴의 예제
- 결제 처리 시스템: 결제 처리 시스템에서 다양한 결제 방법(예: 신용카드, PayPal, 은행 이체)을 선택하고 적용할 수 있도록 전략 패턴을 사용
- 인터페이스 정의:
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
- 구체적인 전략 구현:
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
public class PayPalPayment implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("Paid " + amount + " using PayPal.");
}
}
public class BankTransferPayment implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("Paid " + amount + " using Bank Transfer.");
}
}
- Context 클래스:
public class Order {
private PaymentStrategy paymentStrategy;
public Order(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void processOrder(BigDecimal amount) {
paymentStrategy.pay(amount);
}
}
- 클라이언트 코드:
public class Client {
public static void main(String[] args) {
Order order1 = new Order(new CreditCardPayment());
order1.processOrder(new BigDecimal("100.00"));
Order order2 = new Order(new PayPalPayment());
order2.processOrder(new BigDecimal("200.00"));
Order order3 = new Order(new BankTransferPayment());
order3.processOrder(new BigDecimal("300.00"));
}
}
전략 패턴의 장점
- 알고리즘의 분리: 클라이언트 코드와 알고리즘 구현을 분리하여, 각 알고리즘을 독립적으로 관리할 수 있다.
- 대체 가능성: 클라이언트는 알고리즘을 변경할 때 Context 클래스만 변경하면 되므로, 다양한 알고리즘을 쉽게 대체할 수 있다.
- 코드 중복 감소: 알고리즘을 캡슐화하여, 공통된 알고리즘 코드의 중복을 줄일 수 있다.
전략 패턴의 도메인 주도 설계에서의 활용
- 다양한 도메인 로직 적용: 특정 도메인 개념에 대해 다양한 구현 방법이 존재할 때, 예를 들어, 배송비 계산, 세금 계산 등의 다양한 도메인 로직을 적용할 수 있다.
- 비즈니스 규칙의 유연한 적용: 비즈니스 규칙이 자주 변경되거나, 여러 버전이 존재하는 경우, 전략 패턴을 사용하여 유연하게 비즈니스 규칙을 적용할 수 있다.
- 상황에 따른 행동 변경: 도메인의 상태나 상황에 따라 다른 행동을 적용해야 할 때, 전략 패턴을 사용하여 상황에 맞는 행동을 동적으로 변경할 수 있다.
플라이웨이트 패턴
플라이웨이트 패턴(Flyweight Pattern)이란?
- 플라이웨이트 패턴은 메모리 사용량을 줄이기 위해 공유 가능한 객체를 최대한 활용하는 패턴
- 객체의 상태를 내적 상태(Intrinsic State)와 외적 상태(Extrinsic State)로 분리하여, 내적 상태는 공유하고 외적 상태는 객체 외부에서 관리
- 동일한 객체를 여러 번 생성하는 대신, 공유 가능한 객체를 재사용하여 메모리 사용량을 줄이고 객체 생성의 비용을 최소화
구조
- Flyweight: 플라이웨이트 객체의 인터페이스를 정의
- ConcreteFlyweight: 플라이웨이트 인터페이스를 구현하며, 내적 상태를 저장
- FlyweightFactory: 플라이웨이트 객체를 생성하고 관리하며, 공유 가능한 객체를 제공하는 역할
플라이웨이트 패턴의 중요성
- 메모리 효율성: 객체를 공유함으로써 메모리 사용량을 크게 줄일 수 있다. 이는 특히 많은 객체가 필요한 시스템에서 유용하다.
- 객체 생성 비용 절감: 객체를 재사용함으로써 객체 생성의 비용을 줄일 수 있다. 이는 성능을 최적화하는 데 도움이 된다.
플라이웨이트 패턴의 예제
- 문자 처리 시스템: 문자 처리 시스템에서 각 문자를 객체로 표현할 때, 많은 문자가 반복적으로 사용된다. 플라이웨이트 패턴을 사용하여 동일한 문자 객체를 공유하면 메모리 사용량을 줄일 수 있다.
- 인터페이스 정의:
public interface Flyweight {
void display(int x, int y);
}
- 구체적인 플라이웨이트 구현:
public class CharacterFlyweight implements Flyweight {
private final char character;
public CharacterFlyweight(char character) {
this.character = character;
}
@Override
public void display(int x, int y) {
System.out.println("Character: " + character + " at (" + x + ", " + y + ")");
}
}
- 플라이웨이트 팩토리:
import java.util.HashMap;
import java.util.Map;
public class FlyweightFactory {
private static final Map<Character, Flyweight> flyweights = new HashMap<>();
public static Flyweight getFlyweight(char character) {
flyweights.computeIfAbsent(character, CharacterFlyweight::new);
return flyweights.get(character);
}
}
- 클라이언트 코드:
public class Client {
public static void main(String[] args) {
Flyweight a1 = FlyweightFactory.getFlyweight('a');
Flyweight a2 = FlyweightFactory.getFlyweight('a');
Flyweight b1 = FlyweightFactory.getFlyweight('b');
a1.display(1, 1);
a2.display(2, 2);
b1.display(3, 3);
}
}
플라이웨이트 패턴의 장점
- 메모리 절약: 객체를 공유하여 메모리 사용량을 줄일 수 있다. 이는 특히 많은 수의 객체가 필요한 경우에 유용하다.
- 성능 향상: 객체 생성 비용을 줄여 성능을 최적화할 수 있다. 이는 시스템의 응답 시간을 개선하는 데 도움이 된다.
도메인 주도 설계에서의 활용
- 공유 가능한 상태가 많은 경우: 도메인 모델에서 동일한 상태를 가지는 객체가 많이 생성되는 경우, 플라이웨이트 패턴을 사용하여 객체를 공유할 수 있다. 예를 들어, 동일한 주소를 가지는 여러 고객 객체를 공유할 수 있다.
- 메모리 사용량 최적화가 중요한 경우: 도메인 모델에서 메모리 사용량을 최적화하는 것이 중요한 경우, 플라이웨이트 패턴을 사용하여 메모리 사용량을 줄일 수 있다.
- 예제
- 배송 시스템에서의 주소 공유
public class Address {
private final String street;
private final String city;
private final String zipcode;
public Address(String street, String city, String zipcode) {
this.street = street;
this.city = city;
this.zipcode = zipcode;
}
// Getters, equals, hashCode, toString
}
public class AddressFactory {
private static final Map<String, Address> addresses = new HashMap<>();
public static Address getAddress(String street, String city, String zipcode) {
String key = street + city + zipcode;
addresses.computeIfAbsent(key, k -> new Address(street, city, zipcode));
return addresses.get(key);
}
}
public class Delivery {
private final String deliveryId;
private final Address address;
public Delivery(String deliveryId, Address address) {
this.deliveryId = deliveryId;
this.address = address;
}
// Other methods
}
반응형
LIST
'도서' 카테고리의 다른 글
DDD - 에릭 에반스, (15장 디스틸레이션) (0) | 2024.06.29 |
---|---|
DDD - 에릭 에반스, (14장 모델의 무결성 유지) (0) | 2024.06.29 |
DDD - 에릭 에반스, (11장 분석 패턴의 적용) (0) | 2024.06.29 |
DDD - 에릭 에반스, (10장 유연한 설계) (0) | 2024.06.29 |
DDD - 에릭 에반스, (6장 도메인 객체 생명주기) (0) | 2024.06.29 |