제어의 역전

이한주·2023년 3월 7일
0

IoC

제어의 역전이란 이런 제어의 흐름의 역전이 되는것을 말한다 .

IoC 상황에서는 객체가 자신이 사용할 개체를 스스로 선택하지 않고 스스로 생성도 하지 않는다 .
라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어하지만 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다.

프레임워크가 흐름을 주도하면서 개발자가 만든 애플리케이션 코드를 사용하는 것이다.
즉 , 애플리케이션 코드가 프레임워크가 짜놓은 틀에서 수동적으로 동작한다.

이를 Hollywood Principle이라고도 한다.

예제

현재 실행 클래스에서 Order 엔터티가 사용할 클래스 FixedAmountVoucher를 결정하고 해당 클래스의 객체를 직접 생성한다.

또한 Order 객체도 여기서 직접 생성한다.

즉 모든 종류의 작업을 사용하는 쪽에서 제어를 하는 구조다.

public class OrderTester {

	public static void main(String[] args) {

		var customerId = UUID.randomUUID();
		List<OrderItem> orderItems = new ArrayList<>() {{
				add(new OrderItem(UUID.randomUUID(), 100L, 1));
		}};

		var fixedAmountVoucher = new FixedAmountVoucher(UUID.randomUUID(), 10L);
		var order = new Order(UUID.randomUUID(), customerId, orderItems, fixedAmountVoucher);

		Assert.isTrue(order.totalAmount() == 90L, MessageFormat.format("totalAmount {0} is not 100L", order.totalAmount()));
	}

}

이를 간단하게 애플리케이션의 주요 객체에 대해서 생성과 관계설정을 하는 OrderContext라는 클래스를 정의해서 IoC를 만들어본다.

public class OrderContext {
    public VoucherRepository voucherRepository() {
        return new VoucherRepository() {
            @Override
            public Optional<Voucher> findById(UUID voucherId) {
                return Optional.empty();
            }
        };
    }

    public OrderRepository orderRepository() {
        return new OrderRepository() {
            @Override
            public void insert(Order order) {

            }
        };
    }

    public VoucherService voucherService() {
        return new VoucherService(voucherRepository());
    }

    public OrderService orderService() {
        return new OrderService(voucherService(), orderRepository());
    }
}

이를 이용하는 실행 클래스는 다음과 같다.

public class OrderTester {

	public static void main(String[] args) {

		var customerId = UUID.randomUUID();
		var orderContext = new OrderContext();
		var orderService = orderContext.orderService();
		Order order = orderService.createOrder(customerId, new ArrayList<>() {{
			add(new OrderItem(UUID.randomUUID(), 100L, 1));
		}});

		Assert.isTrue(order.totalAmount() == 100L, MessageFormat.format("totalAmount {0} is not 100L", order.totalAmount()));
	}

}

OrderContext를 통해 OrderTester에서 제어하지 않고 다음과 같이 제어를 역전할 수 있다.

코드

https://github.com/yanJuicy/kdt-spring-order/tree/60fcc7c439320365329ceeea1999895d9be2e240

0개의 댓글