본문 바로가기

Language/JAVA

[이펙티브 자바][아이템 5] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 - 컴도리돌이

728x90

자원을 직접 생성하거나 관리하는 방식은 코드의 유연성과 유지보수성을 크게 제한할 수 있습니다. 자원을 직접 관리하고 명시하는 방식이 실제로는 많은 문제를 초래할 수 있다고 합니다. 왜 그럴까요? 🤔

 

자원을 직접 명시하는 경우, 예를 들어 파일 읽기와 같은 작업을 수행하는 유틸리티 클래스를 작성한다고 가정해 볼게요.

파일을 읽기 위해 BufferedReader를 직접 생성하는 클래스 FileReaderUtil을 만들었다고 생각해 보면, 클래스 내부에서 직접 BufferedReader를 생성하고 관리하는 코드가 들어가죠. 이렇게 되면, 이 클래스는 파일 시스템과 강하게 결합되게 됩니다. 즉, 파일 경로와 파일을 여는 방식이 하드코딩되어 있어, 만약 파일 경로를 바꾸거나 다른 파일 시스템 접근 방식을 사용해야 할 때 클래스 내부 코드를 직접 수정해야 하죠. 이런 접근 방식은 코드의 유연성을 떨어뜨리고 유지보수를 어렵게 만듭니다. 🤨

 

1. 정적 유틸리티 클래스를 사용한 예시

정적 유틸리티 클래스는 유틸리티 메서드와 상수를 제공하는 클래스로, 보통 인스턴스를 생성하지 않고 사용됩니다. 예를 들어, 파일을 읽는 유틸리티 클래스를 다음과 같이 정의할 수 있어요.

public class FileUtil {
    private static final String FILE_PATH = "src/main/resources/data/sample.txt";

    public static String readFile() {
        try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

이 코드에서는 FILE_PATH가 하드코딩되어 있으며, 파일 경로를 직접 클래스에 명시하고 있습니다. 이 방식은 유연성이 부족하고, 파일 경로를 변경하려면 코드 수정을 해야 합니다. 게다가, 테스트하기도 어려워지는데요. 테스트 환경을 구성하려면 실제 파일을 준비하거나, 파일 시스템에 직접 접근해야 하기 때문이죠. 이로 인해 단위 테스트가 복잡해지고, 테스트가 신뢰할 수 없는 결과를 초래할 수 있어요. 😟

 

2. 싱글톤 클래스를 사용한 예시

싱글톤 클래스는 클래스의 인스턴스가 하나만 존재하도록 보장하는 패턴입니다. 자원 관리를 싱글톤으로 처리할 수 있지만, 자원 경로를 클래스에 직접 명시하면 유지보수와 테스트가 어려워질 수 있죠.

public class FileManager {
    private static final FileManager INSTANCE = new FileManager();
    private final String filePath = "src/main/resources/data/sample.txt";

    private FileManager() { }

    public static FileManager getInstance() {
        return INSTANCE;
    }

    public String readFile() {
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

이 코드에서는 filePath가 하드코딩되어 있으며, FileManager 클래스의 인스턴스가 하나만 존재하도록 보장합니다. 그러나 경로가 클래스에 하드코딩되어 있어 유연성이 떨어집니다. 또, 테스트할 때 경로를 쉽게 조정하기 어려워져요.

 

 

[Design Pattern] 싱글톤 패턴(Singleton Pattern)에 대해서 - 컴도리돌이

싱글톤 패턴은 하나의 클래스에 대해 단 하나의 인스턴스만 생성하고, 이를 전역적으로 접근할 수 있도록 하는 디자인 패턴이에요. 싱글톤 패턴을 구현하는 방법은 여러 가지가 있지만, 가장 쉬

comdolidol-i.tistory.com

 


해결책 1 - 필드에서 final 키워드를 제거한다.

final 키워드는 필드의 값을 변경할 수 없게 만듭니다. final 키워드를 제거하면 필드의 값을 변경할 수 있으며, 객체 생성 시 설정할 수 있습니다.

public class ConfigurableFileManager {
    private String filePath;

    public ConfigurableFileManager(String filePath) {
        this.filePath = filePath;
    }

    public String readFile() {
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

filePath 필드가 final이 아니므로, 객체 생성 시 외부에서 파일 경로를 주입할 수 있습니다. 이로 인해 클래스가 더 유연해지고, 테스트하기가 용이해집니다. 하지만 여전히 의존 객체 주입을 통한 더 나은 설계가 가능합니다.

 

해결책 2 - 의존 객체 주입을 사용한다. 

의존 객체 주입을 사용하면, 자원과 객체 생성을 외부에서 관리하고, 설정 파일 등을 통해 유연하게 조정할 수 있습니다.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

@Configuration
public class AppConfig {

    @Value("${file.path}")
    private String filePath;

    @Bean
    public BufferedReader fileReader() throws IOException {
        return new BufferedReader(new FileReader(filePath));
    }
}

 

@Configuration 어노테이션을 사용하여 Spring의 컴포넌트로 등록되며, @Value 어노테이션을 통해 파일 경로를 외부 설정 파일에서 주입을 받습니다. 이렇게 하면, 파일 경로를 하드코딩하는 대신, application.properties 파일에 설정해 둔 경로를 사용할 수 있습니다. 

이렇게 하면 하드코딩된 경로를 설정 파일로 이동시켜, 파일 경로를 변경할 때 애플리케이션 코드를 수정할 필요가 없어져요. 👍

 

 

[Spring] 스프링 제어의 역전(Inversion of Control)과 의존성 주입(Dependency Injection - DI)에 대해서 - 컴도

1. 제어의 역전(Inversion of Control) 정의 및 예제 2. 의존성 주입(Dependency Injection) 정의 및 예제 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성하게 하여 가독성 및 코드의

comdolidol-i.tistory.com


 

자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 는 자원 경로와 객체 생성의 하드코딩을 피하고, 유연하고 유지보수 가능한 코드를 작성하기 위한 방법론입니다. final 키워드를 제거하거나, 의존 객체 주입을 사용하여 자원의 관리와 설정을 외부로 분리하면 코드의 유연성과 테스트 용이성을 크게 향상할 수 있습니다.😄💡