본문 바로가기
코딩log/Spring Framework

[Spring Framework]관심사의 분리 -① Spring없이 개발하기

by 벨크 2023. 1. 29.
반응형

  4차 산업혁명, 디지털 트랜스포메이션 등 이제는 인프라가 IT가 아닌 기업들도 IT기업으로 전환을 하기 시작했습니다. 그만큼 더욱 소프트웨어 개발 및 설계가 중요해지고 있습니다.

 

  소프트웨어 개발과 설계가 중요도가 높아질수록, 객체 설계와 구현이 계속 바뀌게 되었습니다. 심지어 프로젝트가 진행되는 중에도 설계가 변경되기도 합니다. 이런 잦은 변경에 대응하기 위해서는 어떻게 개발을 해야 할까요?

Spring Framework - 관심사의 분리1

Spring 없이 관심사의 분리 구현하기

왜 관심사를 분리하여 개발하여야 하는가?

  소프트웨어의 설계와 구현이 계속해서 변경함에 따라, 우리는 소프트웨어 개발을 할 때 설계의 변경에 따른 구현의 변화를 최소화하여 개발하여야 합니다. 또, 하나의 객체 구현의 변경에 다른 객체도 변경해야 하는 일을 최소화하여야 합니다. 이 것이 좋은 소프트웨어 개발 원칙(SOLID 원칙) 중 하나인 OCP(The Open-Closed Principle: 개방 폐쇄 원칙)입니다.

 

  하지만 일반적인 클래스 설계로는 이 OCP를 지키면서 개발하기가 무척 어렵습니다. 예를 한 번 확인해 보겠습니다.

public interface Car {
    void accelerator();
    
    void breaker();
}

public class Supercar implements Car{
    public void accelerator(){
    //...
    }
    
    public void breaker(){
    //...
    }
}

public class Suvcar implements Car{
    public void accelerator(){
    //...
    }
    
    public void breaker(){
    //...
    }
}

  위와 같이 Car라는 객체 인터페이스를 선언하고, Car의 구현을 각가 Supercar와 Suvcar로 나누어 구현하였습니다. 다음으로 운전자라를 객체를 구현할 텐데요. 운전자 객체는 간단하게, 자동차를 가지고 운전하기와 주차하기를 수행할 수 있는 객체로 구현해 보도록 하겠습니다.

public class Driver {

    private final Car car = new Supercar();
    
    public void driving(){
    	car.accelerator();
        ....
    }
    
    public void parking(){
        ....
    }
}

  운전자는 자동차를 가지고 운전을 하고, 주차를 하기 때문에 자동차의 인터페이스를 이용하게 됩니다. 그런데 이 코드를 보시면, 자동차의 인터페이스뿐만 아니라 구현체인 슈퍼카까지 운전자 객체가 알아야 하는 것을 알 수 있습니다. 이렇게 되면, 전체 소프트웨어 정책이 슈퍼카에서 SUV자동차로 변경이 될 때, 운전자 객체의 구현까지 변경해야 됩니다.

 

  이는 SOLID원칙 중 OCP를 위반할 뿐만 아니라, DIP(Dependency Inversion Principle:의존관계 역전 원칙)까지 위반하게 됩니다. 운전자라는 클라이언트 객체가 자동차의 추상화에 의존하는 것이 아니라, 슈퍼카라는 구현체에 의존하기 때문입니다.

 

  왜 클라이언트 객체가 인터페이스뿐만 아니라 구체 클래스까지 알아야 할까요? 그렇다면, 클라이언트 객체가 구현체에 의존하지 않고, 추상화에만 의존하게 하려면 어떻게 해야 할까요? 한 객체의 구현 변경에 다른 객체가 영향을 받지 않으려면 어떻게 해야 할까요? 해결법은 관심사의 분리에 있습니다.

관심사의 분리 - 의존관계 주입(Dependency Injection)

  위와 같은 클래스 설계에서 OCP, DIP를 지키려면 어떻게 해야 할까요? 바로 구현 객체를 생성하고, 연결하는 별도의 Class를 만들어서 해결하면 됩니다.

public Class AppConfig {

    public Car car() {
        return new Sportcar()
    }
}

public class Driver {

    private final Car car;
    
    public Driver(){
        AppConfig appConfig = new AppConfig();
        this.car = appConfig.car();
    }
    
    public void drive(){
        car.accelerator();
    }
    
    public void parking(){
        ....
    }
}

  위와 같이 AppConfig라는 클래스를 하나 생성합니다. 이 클래스는 각각의 객체를 생성하고, 구현체를 선택하여 연결합니다. Car라는 추상객체에 Sportcar라는 구현 객체를 연결시켜 놓았습니다. 이렇게 되면 운전자 객체를 구현할 때, 운전자 객체는 자동차 객체가 어떤 구현 객체를 의존하고 있는지 알 수 없는 상태에서, 자동차의 추상에만 의존하여 운전자 객체를 구현할 수 있습니다. Client 객체가 특정 클래스의 구현과 무관하게 개발할 수 있게 되는 것입니다.

 

  그럼 위의 코드가 SOLID원칙의 OCP와 DIP를 잘 지키고 있는지 확인해 보겠습니다. 자동차 객체의 구현을 Sportcar에서 Suvcar로 변경해 봅시다. AppConfig 만 수정하고, Driver 객체의 코드는 변경이 없습니다. OCP를 잘 지키고 있게 됩니다. 또 Dirvier 객체의 소스 코드를 보면, Car객체의 추상화에 의존하지만, 어디에도 구현체를 찾아볼 수 없습니다. DIP를 잘 지키게 되는 것입니다.

 

  정리해 보면, AppConfig라는 클래스가 구현체를 할당하는 역할을 하기 때문에 각자의 객체는 본인의 역할을 수행하는데 집중할 수 있게 됩니다. 그리고 의존 관계에 있는 객체에 추상에만 의존하여, 해당 객체의 구현은 모르는 상태로 객체의 기능을 실행하기만 하면 됩니다.

 

  AppConfig 같은 클래스가 마치 외부에서 제삼자가 의존관계를 주입하는 거처럼 보여서 이를 의존관계 주입(Dependency Injection)이라고 합니다.

 

  의존관계 주입(DI: Dependency Injection)을 제어의 역전(IoC)라고 부르기도 합니다. 과연 제어의 역전은 무엇인지, 또 스프링과는 무슨 연관이 있는지 다음번에 간단히 공부해 보고, 본격적으로 스프링을 이용하여 의존관계 주입을 구현해 보도록 하겠습니다.

 

Prev: 스프링 시작하기 - 스프링부트 설치하기

 

[Spring Framework]스프링 시작하기 -스프링 부트 설치하기

본격적으로 스프링 프레임워크를 이용해 개발을 시작해 보겠습니다. 스프링을 이용해 개발을 하기 위해서는 당연히 스프링을 설치해야겠죠. 예전에는 스프링 및 스프링의 핵심 기능을 사용하

belklog.tistory.com

반응형

댓글