DI와 디자인 패턴

2024. 7. 4. 16:50토비의 스프링 6

디자인 패턴을 구분하는 두 가지 방식이 있다.

하나는 사용 목적(purpose)이고 다른 하나는 스코프(scope)이다.

스코프에 의해서 분류하면 클래스 패턴과 오브젝트 패턴으로 나눌 수 있다.

클래스 패턴은 상속(inherence)을 이용해서 확장성을 가진 패턴으로 만들어지고, 오브젝트 패턴은 합성(composition)을 이용한다. 대부분의 디자인 패턴은 오브젝트 패턴이다. 가능하면 오브젝트 합성을 상속보다 더 선호하라는 디자인 패턴의 기본 객체지향 원리를 따른 것이다.

 

오브젝트 합성을 이용하는 디자인 패턴을 적용할 때 스프링의 의존관계 주입(Dependenct Injection)을 사용

 

WebApiExRateProvider에 캐시 기능을 추가하려면?

WebApiExRateProvider 코드 수정

->데코레이터(Decorator) 디자인 패턴 : 오브젝트에 부가적인 기능/책임을 동적으로 부여한다.

  • CachedExRateProvider를 사용할 때 WebApiExRateProvider를 불러와야한다.

 

 

 

최종 구조

 

 

 

CachedExRateProvider

package tobyspring.hellospring;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;

public class CachedExRateProvider implements ExRateProvider{
    private final ExRateProvider target;
    private BigDecimal cachedExRate;
    private LocalDateTime cachedExpiryTime;

    public CachedExRateProvider(ExRateProvider target) {
        this.target = target;
    }

    @Override
    public BigDecimal getExRate(String currency) throws IOException {
        if(cachedExRate==null || cachedExpiryTime.isBefore(LocalDateTime.now())){
            cachedExRate=this.target.getExRate(currency);
            cachedExpiryTime = LocalDateTime.now().plusSeconds(3);

            System.out.println("Cache Updated");
        }
        return cachedExRate;
    }
}

 

ObjectFactory

package tobyspring.hellospring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ObjectFactory {
    @Bean
    public PaymentService paymentService() {
        return new PaymentService(cachedExRateProvider());
    }

    @Bean
    public ExRateProvider cachedExRateProvider(){
        return new CachedExRateProvider(exRateProvider());
    }

    @Bean
    public ExRateProvider exRateProvider(){
        return new SimpleExRateProvider();
    }
}

 

Client

package tobyspring.hellospring;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        BeanFactory beanFactory = new AnnotationConfigApplicationContext(ObjectFactory.class);
        PaymentService paymentService = beanFactory.getBean(PaymentService.class);

        Payment payment1 = paymentService.prepare(100L,"USD", BigDecimal.valueOf(50.7));
        System.out.println("Payment1 : " + payment1);
        System.out.println("-----------------------------------------------\n");

        TimeUnit.SECONDS.sleep(3);

        Payment payment2 = paymentService.prepare(100L,"USD", BigDecimal.valueOf(50.7));
        System.out.println("Payment2 : " + payment2);
    }
}