의존성 주입 정리

14287 단어 JavaStrategyJava

의존성 주입이란

소프트웨어 엔지니어링에서 의존성 주입(dependency injection)은 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉이다.
"의존성"은 예를 들어 서비스로 사용할 수 있는 객체이다. 클라이언트가 어떤 서비스를 사용할 것인지 지정하는 대신, 클라이언트에게 무슨 서비스를 사용할 것인지를 말해주는 것이다. "주입"은 의존성(서비스)을 사용하려는 객체(클라이언트)로 전달하는 것을 의미한다.
[위키백과]

자바에서 프로그램을 개발할 때 한 클래스내에서 모든 코드를 구현할 수 있지만 그건 자바다운 개발이 아닙니다. 클래스를 역할과 책임을 통해 분할하고, 필요한 객체끼리 서로 협력하는 구조가 가장 이상적입니다.

1. 구현방법

저의 토이프로젝트인 체스게임에서 의존성주입을 구현한 코드를 소개하겠습니다. 다음 코드는 체스게임의 Player객체의 일부 코드입니다.

public final class HumanPlayer implements Player {
    private final PlayerType playerType;
    private final UI ui;
    private final ChessBoard chessBoard;

    public HumanPlayer(PlayerType playerType, UI ui, ChessBoard chessBoard) {
        this.playerType = playerType;
        this.ui = ui;
        this.chessBoard = chessBoard;
    }
    
    // More codes...
}

Player객체가 게임을 플레이하기 위해서는 게임 상의 여러객체에게 필요한 요청을 해야합니다. 현재 객체에선 UI객체에게 사용자 명령을 받고 기물을 움직이거나 기권 시 게임을 종료하고 ChessBoard객체에게 기물을 이동할 것을 요청하게 됩니다. 여기서 Plyaer객체의 의존성은 UI와 ChessBoard입니다.

UI, ChessBoard 멤버변수를 정의하고 외부에서 객체를 생성하고 주입해주는 패턴을 사용하고 있습니다. 즉 생성자를 사용해서 객체를 만들 때 필요한 객체를 넘겨주는 겁니다.

이러한 기법을 의존성 주입(Defendency Injection)이라고 합니다.

public final class AppConfig {
    private final ChessGameNotation CHESS_GAME_NOTATION = new ChessGameNotation();
    private final Rule RULE = new ChessRule(chessGameNotation());
    private final ChessBoardSetting CHESS_BOARD_SETTING = new ChessBoardSetting();
    private final ChessPromotionManager CHESS_PROMOTION_MANAGER = new ChessPromotionManager();
    private final ChessBoard CHESS_BOARD = new ChessBoard(rule(), chessBoardSetting(), chessPromotionManager());
    private final OSVerifier OS_VERIFIER = new OSVerifier();
    private final Scanner SCANNER = new Scanner(System.in);
    private final BoardPrinter BOARD_PRINTER = new BoardPrinter(osVerifier());
    private final ConsoleFormatter CONSOLE_FORMATTER = new ConsoleFormatter();
    private final ChessUI CHESS_UI = new ChessUI(scanner(), boardPrinter(), consoleFormatter());

    private ChessGameNotation chessGameNotation() {
        return CHESS_GAME_NOTATION;
    }

    private Rule rule() {
        return RULE;
    }

    private ChessBoardSetting chessBoardSetting() {
        return CHESS_BOARD_SETTING;
    }

    private ChessPromotionManager chessPromotionManager() {
        return CHESS_PROMOTION_MANAGER;
    }

    private ChessBoard chessBoard() {
        return CHESS_BOARD;
    }

    private OSVerifier osVerifier() {
        return OS_VERIFIER;
    }

    private Scanner scanner() {
        return SCANNER;
    }

    private BoardPrinter boardPrinter() {
        return BOARD_PRINTER;
    }

    private ConsoleFormatter consoleFormatter() {
        return CONSOLE_FORMATTER;
    }

    private UI ui() {
        return CHESS_UI;
    }

    public Player createPlayer(PlayerType playerType) {
        return new HumanPlayer(playerType, ui(), chessBoard());
    }
}

필요한 의존성 객체는 AppConfig.java에서 해당 객체와 관계를 맺는 모든 객체까지 생성한 뒤 플레이어 객체를 반환해주는 createPlayer()메서드를 제공합니다. 해당 메서드를 호출해서 게임플레이에 필요한 플레이어객체를 생성할 수 있습니다.

이렇게 객체생성을 따로 관리할 경우 객체의 생성과 사용을 분리되어서 좀더 OOP다운 코드를 짤 수 있습니다. 객체의 생성은 외부에 맡기고 객체 자신의 역할에만 집중 할 수 있습니다.

만약 스프링 프레임워크를 사용한다면 의존성관리를 좀 더 손쉽게 할 수 있지만 해당 토이프로젝트는 순수하게 자바로 개발된 프로젝트이기에 쓰지는 않았습니다.

나중에 기회가 된다면 스프링 프레임워크에서 사용하는 의존성 관리에 대해서 다뤄보겠습니다.

감사합니다!

좋은 웹페이지 즐겨찾기