자바 Impl 클래스 만드는 이유

자바(Java) 패키지 구성을 보면 ***Impl.class 형태의 파일들을 볼 수 있습니다. 예를 들어, DatabaseService.class가 있으면 DatabaseServiceImpl.class 같은 클래스 파일도 함께 있는 식입니다.

implementation

Impl은 구현(implementation)의 줄임 표현으로, 종종 자바 클래스 이름의 일부로 사용됩니다. 주로 인터페이스를 구현하는 클래스를 만들 때 이런 방식으로 클래스 이름을 만듭니다.

 

예를 들어, List라는 인터페이스가 있을 때, 이를 구현하는 클래스는 ListImpl이라는 이름으로 생성해서 사용합니다. Impl이라고 표시함으로써 인터페이스를 구현을 위한 클래스라는 걸 명확히 보여줍니다. 물론 네이밍 방식은 정해진 게 없으니 Impl 대신 다른 명칭을 쓸 수도 있습니다.

 

Impl 클래스 사용 이유

중요한 건 왜 인터페이스와 구현체(Impl)를 분리하여 만들어서 사용하는가 입니다. 이는 자바의 특성인 객체지향 프로그래밍 개념과 연관이 있습니다. Impl 클래스를 사용하면 몇 가지 이점이 있습니다.

 

1. 인터페이스를 사용하면, 특정 기능에 대한 여러 가지 구현을 쉽게 변경하거나 교체할 수 있습니다. 구현체를 수정하더라도 다른 코드에 영향을 거의 주지 않습니다.

 

2. 인터페이스를 통해 가짜 객체 (모의 객체)를 쉽게 만들어 단위 테스트를 진행할 수 있습니다.

 

3. 인터페이스를 사용하면 구현 세부사항을 캡슐화하고 클라이언트 코드에서 숨길 수 있습니다.

 

4. 인터페이스를 사용하면 다형성을 활용할 수 있습니다. 즉, 인터페이스를 통해 다양한 구현체를 다룰 수 있게 되며, 이를 통해 코드의 재사용성과 확장성을 향상시킬 수 있습니다.

 

예시)

인터페이스와 구현 클래스를 사용하는 간단한 Java 예제를 확인해보겠습니다.

 

먼저 데이터베이스에서 정보를 가져오는 간단한 DatabaseService 인터페이스를 만들어보겠습니다.

public interface DatabaseService {
    String getData();
}

 

이제 이 인터페이스를 구현하는 클래스를 만들 수 있습니다. MySQL에서 데이터를 가져오는 경우라고 가정하고 MySQLDatabaseServiceImpl이라는 이름의 클래스를 만듭니다.

public class MySQLDatabaseServiceImpl implements DatabaseService {
    @Override
    public String getData() {
        // MySQL에서 데이터를 가져오는 로직이 들어가는 부분
        return "Data from MySQL";
    }
}

 

만약 Postgre에서 데이터를 가져오는 서비스가 추가로 필요할 수도 있습니다. 그럼 PostgreSQLDatabaseServiceImpl이라는 구현체를 추가로 만들 수 있습니다.

public class PostgreSQLDatabaseServiceImpl implements DatabaseService {
    @Override
    public String getData() {
        // PostgreSQL에서 데이터를 가져오는 로직이 들어가는 부분
        return "Data from PostgreSQL";
    }
}

 

이러한 구현체를 사용하는 Client 클래스는 아래와 같이 쓸 수 있습니다.

public class Client {
    private DatabaseService databaseService;

    // 인터페이스를 통해 구현체를 주입
    public Client(DatabaseService databaseService) {
        this.databaseService = databaseService;
    }

    public void fetchData() {
        String data = databaseService.getData();
        System.out.println(data);
    }
}

 

이 방식으로 Client 클래스는 MySQL, PostgreSQL 각각 DatabaseService의 구현체를 모두 쓸 수 있습니다. Client 클래스를 변경하지 않아도 됩니다.

public static void main(String[] args) {
    DatabaseService mySQLService = new MySQLDatabaseServiceImpl();
    Client client1 = new Client(mySQLService);
    client1.fetchData(); 
      // Output: "Data from MySQL"

    DatabaseService postgreSQLService = new PostgreSQLDatabaseServiceImpl();
    Client client2 = new Client(postgreSQLService);
    client2.fetchData(); 
        // Output: "Data from PostgreSQL"
}

 

이처럼 인터페이스와 구현 클래스를 사용하면 유연성을 높이고 코드의 유지 관리를 용이하게 만듭니다.

반응형

댓글

Designed by JB FACTORY