Back-End/Spring

[Spring] 강한 결합(Tight Coupling)과 느슨한 결합(Loose Coupling)

유자맛바나나 2021. 7. 4. 01:40

의존성 주입(DI: Dependency Injection)과 IoC(Inversion Of Control) 컨테이너는 Spring의 기본이자 핵심 기능 중 하나다.
Spring을 이해하기 위해서 가장 먼저 학습해야할 내용이다.
DI를 배우기에 앞서 강한 결합 대비 느슨한 결합의 이점을 보며 외부 의존성 주입(DI)의 필요성에 대해 학습할 필요가 있다. 
 

❑ 강한 결합(Tight Copuling)

Class Diagram

Code Example

AS-IS) GasolineEngine 참조

public class Car {
    private GasolineEngine gasolineEngine = new GasolineEngine();
    
    public void ride() {
        gasolineEngine.useOil();
        ...
    }
}

public class GasolineEngine {
    public void useOil() {}
}

TO-BE) ElectricMotor 참조

public class Car {
    private ElectricMotor electricMotor = new ElectricMotor();
    
    public void ride() {
        electricMotor.useBattery();
        ...
    }
}

public class ElectricMotor {
    public void useBattery() {}
}

강한 결합은 구현 클래스(Concrete Class)를 직접 참조하는 것이다. 
AS-IS에서 Car는 GasolineEngine을 직접 참조하고 있기 때문에 강한 결합 상태라고 할 수 있고, Gasoline 전용 차량으로 작동한다.
만약 TO-BE 처럼 ElectricMotor를 장착할 경우 Car 클래스는 어떻게 변할까? 우선 GasolineEngine을 ElectricMotor 클래스로 변경한다. 그리고 ElectricMotor는 Oil이 아닌 Battery를 사용하기 때문에 ride 메서드도 역시 변경되어야 한다. 이렇듯, 강한 결합은 Client 코드에 많은 변경을 요구한다.
 
여기서 가져야할 바람직한 의문점
Car는 반드시 동력장치가 GasolineEngine인지, ElectricMotor인지 알아야할까? 그저 '동력장치'에게 '동력원(Oil, Battery)'을 사용해달라고 요청만 하면 되는것 아닐까? GasolineEngine과 ElectricMotor를 추상화한 인터페이스가 그 역할을 해줄 수 있다!
 

❑ 느슨한 결합(Loose Coupling, 인터페이스 활용)

느슨한 결합력이란 클래스 간 결합력을 약하게 만들었다는 뜻이다. 약한 결합은 구현 클래스를 직접 참조하는 강한 결합과 달리 '추상화'에 의존한다. 결합도의 관점에서 구체 클래스 의존에서 인터페이스 의존으로 갈수록 Client가 알아야 할 지식의 양이 적어지므로 결합도가 느슨해진다.

  • 구체 클래스 의존성(Concrete Class Dependency)
  • 추상 클래스 의존성(Abstract Class Dependency)
  • 인터페이스 의존성(Interface Dependency)

 

Class Diagram

Code Example

Interface) PowerUnit

public interface PowerUnit {
    void useSource();
}

AS-IS) GasolineEngine 참조

public class Car {
    private PowerUnit powerUnit = new GasolineEngine();
    
    public void ride() {
        powerUnit.useSource();
        ...
    }
}

public class GasolineEngine implements PowerUnit {
    @Override
    public void useSource() {}
}

TO-BE) ElectricMotor 참조

public class Car {
    private PowerUnit powerUnit = new ElectricMotor();
    
    public void ride() {
        powerUnit.useSource();
        ...
    }
}

public class ElectricMotor implements PowerUnit {
    @Override
    public void useSource() {}
}

강한 결합과 달리 GasolineEngine/ElectricMotor에 따라 Car 클래스에서 변경될 코드는 powerUnit에 인스턴스를 주입하는 부분 뿐이다. Car는 PowerUnit으로 받는 객체가 GasolineEngine인지, ElectricMotor인지만 알면 되고, 각각 PowerUnit의 구현체이므로 강제되는 useSource만 이용하면 된다.
 
이렇듯 느슨한 결합은 Client 코드의 변경점을 크게 줄여줄 수 있다. 하지만 여전히 Car 클래스는 GasolineEngine/ElectricMotor를 알고 있어야하므로 강한 결합에서 가진 의문점을 해소하지 못했다. 이는 GasolineEngine/ElectricMotor라는 의존 클래스를 new를 이용해 직접 주입하고 있기 때문이다.
 
Car 클래스가 의존 클래스를 외부에서 주입해주는 의존성 주입(DI)을 통해 Car는 비로소 powerUnit 인스턴스 주입 부분마저 수정할 필요가 없어진다.
 
2021.07.16 - [Back-End/Spring] - [Spring] 의존성 주입(DI)과 IoC 컨테이너의 개념 포스팅에서 확인해보자
 

❑ Referece

오브젝트(Object) | 위키북스, 조영호