About Inversion of Control

koonlx·2024년 11월 5일

Spring

목록 보기
4/7

IoC(Inversion of Control, 제어의 역전)은 소프트웨어 설계 원칙 중 하나로, 객체의 생성 및 제어 권한을 개발자가 직접 다루는 것이 아니라 외부에서 처리하도록 하는 개념이다.
이를 통해 모듈 간의 결합도를 낮추고, 코드의 재사용성과 확장성을 높이는 것이 핵심 목표이다.

IoC의 핵심 개념

  1. 제어의 역전(Inversion): 전통적인 절차 지향적 프로그램에서는 객체가 스스로 자신을 생성하고 필요에 따라 동작을 수행한다. 그러나 IoC에서는 객체의 제어권을 IoC 컨테이너와 같은 외부 시스템이 가지고, 필요한 객체를 생성 및 주입한다.
  2. 의존성 주입(Dependency Injection): IoC의 구현 방법 중 하나로, 클래스가 다른 클래스에 의존할 때, 필요한 객체를 직접 생성하는 대신 외부에서 주입받는 방식이다. 이를 통해 객체 간의 의존성을 줄이고, 코드의 유연성을 높인다.
  3. 느슨한 결합(Loose Coupling): IoC는 코드의 결합도를 낮추어 모듈화된 구조를 촉진한다. 이로 인해 유지 보수가 용이하고 코드의 변경이 더 쉽게 이루어진다.

Java Example Code

Simple Version

  • 인터페이스 정의
public interface PaymentService {
	void processPayment();
}
  • 인터페이스 구현 클래스
public class CreditCardPaymentService implements PaymentService {
	@Override
    public void processPayment() {
    	System.out.println("Processing payment through Credit Card");
    }
}
public class PaypalPaymentService implements PaymentService {
	@Override
    public void processPayment() {
    	System.out.println("Processing payment through Paypal");
    }
}
  • OrderService 클래스
public class OrderService {
	private PaymentService paymentService;
    
    public OrderService(PaymentService paymentService) {
    	this.paymentService = paymentService;
    }
    
    public void placeOrder() {
    	System.out.println("Placing order...");
        paymentService.processPayment();
    }
}
  • IoC 컨테이너
public class IoCContainer {
	public static PaymentService getPaymentService(String type) {
    if (type.equals("credit")) {
    	return new CreditCardPaymentService();
    } else if (type.equals("paypal")) {
    	return new PaypalPaymentService();
    }
    throw new IllegalArgumentException("Unknown payment type");
}
  • Main에서 실행
public class Main {
	public static void main(String[] args) {
    	PaymentService paymentService = IoCContainer.getPaymentService("credit");
        
        OrderService orderService = new OrderService(paymentService);
        orderService.placeOrder();
    }
}

Deepening Version

  • 인터페이스 정의
public interface PaymentService {
	void processPayment();
}
  • 인터페이스 구현 클래스
public class CreditCardPaymentService implements PaymentService {
	@Override
    public void processPayment() {
    	System.out.println("Processing payment through Credit Card");
    }
}
public class PaypalPaymentService implements PaymentService {
	@Override
    public void processPayment() {
    	System.out.println("Processing payment through Paypal");
    }
}
  • IoC 컨테이너
import java.util.HashMap;
import java.util.Map;

public class SimpleIoCContainer {
	private Map<Class<?>, Object> beanMap = new HashMap<();
    
    // 객체 등록
    public void registerBean(Class<?> clazz, Object bean) {
    beanMap.put(clazz, bean);
    
    // 객체 가져오기
    public <T> T getBean<Class<T> clazz) {
    	return clazz.cast(beanMap.get(clazz));
    }
    
    // 객체 생성 및 등록 (생성자 주입 방식)
    public void registerBeanWithDependencies(Class<?> clazz, Class<?> dependencyClass) {
    	try {
        	Object dependency = getBean(dependencyClass);
            Object instance = clazz.getConstructor(dependencyClass).newInstance(dependency);
            registerBean(clazz, instance);
        } cath (Exception e) {
        	throw new RuntimeException("Failed to create bean with dependencies", e);
        }
    }
}
  • 의존성을 주입받는 OrderService 클래스
public class OrderService {
	private PaymentService paymentService;
    
    public OrderService(PaymentService paymentService) {
    	this.paymentService = paymentService;
    }
    
    public void placeOrder() {
    	System.out.println("Placing order...");
        paymentService.processPayment();
    }
}
  • IoC 컨테이너를 이용한 의존성 주입 및 객체 관리
public class Main {
	public static void main(String[] args) {
    	SimpleIoCContainer container = new SimpleIoCConatiner();
        
        container.registerBean(PaymentService.class, new CreditCardPaymentService());
        
        container.registerBeanWithDependencies(OrderService.class, PaymentService.class);
        
        OrderService orderService = container.getBean(OrderService.class);
        orderService.placeOrder();
    }
}

설명

  • SimpleIoCContainer는 간단한 IoC 컨테이너 역할을 하며, 객체를 등록하고 의존성을 주입할 수 있다.
  • registerBean() 메서드는 특정 클래스와 객체를 매핑하여 저장한다.
  • registerBeanWithDependencies() 메서드는 의존성을 주입하여 객체를 생성하고 등록한다.
  • 이 방식은 Spring IoC 컨테이너의 기본 원리를 구현한 것이다.
    Spring은 더 복잡한 설정과 라이프사이클 관리, 어노테이션 기반의 자동 주입 기능을 제공하지만, 이 예제는 기본 개념을 구현한 것이다.
profile
Server Developer

0개의 댓글