프로젝트

일반

사용자정보

GRASP 패턴: Indirection (간접성)

Prof. Jong Min Lee이(가) 약 한달 전에 추가함

GRASP 패턴: Indirection (간접성) - 간단한 설명과 예시

핵심 아이디어: 두 객체 사이의 직접적인 결합을 피하기 위해 중간 객체를 도입하여 책임을 할당합니다. 이 중간 객체는 두 객체 사이의 통신을 중재하거나, 인터페이스 역할을 수행하여 결합도를 낮추고 유연성을 높입니다.

간단한 설명:

직접적인 결합은 한 객체의 변경이 다른 객체에 직접적인 영향을 미칠 수 있어 시스템의 유지보수성과 확장성을 저해합니다. 간접성 패턴은 이러한 직접적인 의존성을 줄이기 위해 중간에 또 다른 객체를 도입합니다. 이 중간 객체는 클라이언트와 서비스 제공자 사이의 계약(인터페이스)을 정의하거나, 요청을 처리하는 방식을 추상화하여 양쪽 객체의 변화에 대한 영향을 최소화합니다.

예시:

사용자 인터페이스(UI)와 데이터베이스 간의 직접적인 통신을 생각해 봅시다. UI 객체가 특정 데이터베이스 클래스에 직접적으로 의존하여 데이터를 저장하고 조회하는 경우, 데이터베이스 종류가 변경되면 UI 코드 전체를 수정해야 할 가능성이 큽니다. 이는 높은 결합도의 문제입니다.

간접성 패턴을 적용하여 이 문제를 해결할 수 있습니다. 데이터베이스와 UI 사이에 데이터 접근 객체 (Data Access Object, DAO) 라는 중간 객체를 도입하는 것입니다.

// 사용자 인터페이스 (UI) 클래스
class UserInterface {
    private UserDAO userDAO; // 직접적인 데이터베이스 접근 대신 DAO에 의존

    public UserInterface(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public User getUserDetails(String userId) {
        return userDAO.getUserById(userId);
    }

    public void saveUser(User user) {
        userDAO.saveUser(user);
    }
}

// 데이터 접근 객체 (DAO) 인터페이스
interface UserDAO {
    User getUserById(String userId);
    void saveUser(User user);
    // ... 다른 데이터 접근 관련 메서드 ...
}

// 구체적인 데이터베이스 접근 객체 (예: MySQL)
class MySQLUserDAO implements UserDAO {
    private MySQLDatabaseConnection dbConnection;

    public MySQLUserDAO(MySQLDatabaseConnection dbConnection) {
        this.dbConnection = dbConnection;
    }

    @Override
    public User getUserById(String userId) {
        // MySQL 데이터베이스에서 사용자 정보 조회 로직
        System.out.println("MySQL에서 사용자 " + userId + " 정보 조회");
        return new User(userId, "John Doe"); // 예시
    }

    @Override
    public void saveUser(User user) {
        // MySQL 데이터베이스에 사용자 정보 저장 로직
        System.out.println("MySQL에 사용자 " + user.getId() + " 정보 저장");
        // ...
    }
}

// 구체적인 데이터베이스 접근 객체 (예: Oracle)
class OracleUserDAO implements UserDAO {
    private OracleDatabaseConnection dbConnection;

    public OracleUserDAO(OracleDatabaseConnection dbConnection) {
        this.dbConnection = dbConnection;
    }

    @Override
    public User getUserById(String userId) {
        // Oracle 데이터베이스에서 사용자 정보 조회 로직
        System.out.println("Oracle에서 사용자 " + userId + " 정보 조회");
        return new User(userId, "Jane Doe"); // 예시
    }

    @Override
    public void saveUser(User user) {
        // Oracle 데이터베이스에 사용자 정보 저장 로직
        System.out.println("Oracle에 사용자 " + user.getId() + " 정보 저장");
        // ...
    }
}

// 도메인 객체
class User {
    private String id;
    private String name;

    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

// 데이터베이스 연결 클래스 (예시)
class MySQLDatabaseConnection { /* ... */ }
class OracleDatabaseConnection { /* ... */ }

public class Client {
    public static void main(String[] args) {
        // MySQL 데이터베이스 사용
        UserDAO mysqlUserDAO = new MySQLUserDAO(new MySQLDatabaseConnection());
        UserInterface uiWithMySQL = new UserInterface(mysqlUserDAO);
        uiWithMySQL.getUserDetails("123");
        uiWithMySQL.saveUser(new User("456", "Peter Pan"));

        System.out.println("--- 데이터베이스 변경 ---");

        // Oracle 데이터베이스로 변경 (UI 코드 변경 없음)
        UserDAO oracleUserDAO = new OracleUserDAO(new OracleDatabaseConnection());
        UserInterface uiWithOracle = new UserInterface(oracleUserDAO);
        uiWithOracle.getUserDetails("789");
        uiWithOracle.saveUser(new User("012", "Alice"));
    }
}

이 예시에서 UserDAO 인터페이스가 간접적인 역할을 수행합니다.

  • UserInterface는 구체적인 데이터베이스 클래스 (MySQLDatabaseConnection, OracleDatabaseConnection)에 직접적으로 의존하는 대신, UserDAO라는 인터페이스에 의존합니다.
  • UserDAO 인터페이스는 데이터 접근에 필요한 기본적인 동작 (getUserById, saveUser)을 정의합니다.
  • MySQLUserDAOOracleUserDAOUserDAO 인터페이스를 구현하여 각각 MySQL과 Oracle 데이터베이스와의 통신을 처리하는 구체적인 방법을 제공합니다.

간접성의 장점:

  • 낮은 결합도: UserInterface는 특정 데이터베이스 구현체에 대한 지식이 없으므로 결합도가 낮아집니다. 데이터베이스가 변경되더라도 UserInterface 코드를 수정할 필요가 거의 없습니다.
  • 유연성: 시스템을 다양한 데이터베이스 환경에 쉽게 적용할 수 있습니다. 새로운 데이터베이스를 지원해야 할 경우, 해당 데이터베이스를 위한 새로운 UserDAO 구현체만 만들면 됩니다.
  • 재사용성: UserDAO 인터페이스는 다양한 UI 컴포넌트에서 재사용될 수 있습니다.
  • 테스트 용이성: 인터페이스를 기반으로 Mock 객체를 만들어 UI 로직을 데이터베이스 의존성 없이 독립적으로 테스트할 수 있습니다.

결론적으로, 간접성 패턴은 중간 객체를 도입하여 객체 간의 직접적인 결합을 줄임으로써 시스템의 유연성, 확장성, 유지보수성 및 테스트 용이성을 향상시키는 중요한 설계 원칙입니다. DAO 패턴 외에도 Mediator, Observer 등 다양한 디자인 패턴에서 간접성 개념이 활용됩니다.