728x90

관심사 분리와 확장성 확보

두 개의 관심사를 독립시키면서 동시에 손쉽게 확장할 수 있는 방법

방법은 간단하다. DB 커넥션과 관련된 부분을 서브클래스가 아닌 별도의 클래스에 담으며 이렇게 만든 클래스를 UserDao가 이용하면 됩니다.

1. 관심사 분리

관심사 분리는 소프트 웨어 디자인 원칙 중 하나로, 프로그램을 여러 부분으로 나누어 각 부분이 특정한 관심사에 집중하도록 하는 것을 말합니다. 코드의 유지보수성과 가독성을 향상하고, 코드의 재사용성을 높이는데 도움이 됩니다.

2. 확장성 확보

확장성은 시스템이 늘어나는 요구사항에 대해 적절히 대응할 수 있는 능력을 말합니다. 소프트웨어 시스템은 초기 설계 시 확장성을 고려하여야 하며, 확장성을 고려하지 않은 시스템은 새로운 요구사항이나 사용자 증가에 쉽게 대응하기 어렵습니다.

 

public class UserDao {
    private Connection connection;

    public UserDao() {
        // DB 커넥션을 초기화하는 코드
        this.connection = DBConnection.getConnection();
    }

    public void saveUser(User user) {
        // 사용자 정보를 DB에 저장하는 코드
    }

    public User getUserById(int userId) {
        // 사용자 정보를 DB에서 조회하는 코드
        return null;
    }
}

UserDao 클래스에서는 DB 커넥션을 이용하는 방식으로 변경됩니다.

public class UserDao {
    public void saveUser(User user) {
        Connection connection = DBConnection.getConnection();
        // 사용자 정보를 DB에 저장하는 코드
    }

    public User getUserById(int userId) {
        Connection connection = DBConnection.getConnection();
        // 사용자 정보를 DB에서 조회하는 코드
        return null;
    }
}

위처럼 DB 커넥션 부분을 별도의 클래스로 분리하면, UserDao  클래스는 DB에 접근하는 방식에만 집중할 수 있게 됩니다. 이렇게 하면 DB 커넥션 관련 기능을 변경하거나 확장해야 할 때 DBConnection 클래스만 수정하면 되므로 확장성이 높아집니다.

 

인터페이스 도입

자바가 추상화를 하기 위해 제공하는 가장 유용한 도구는 인터페이스입니다. 인터페이스는 자신을 구현한 클래스에 대한 구체적인 정보는 모두 감춰버립니다. 결국 오브젝트를 만들려면 구체적인 클래스 하나를 선택해야겠지만 인터페이스로 추상화해 놓은 최소한의 통로를 통해 접근하는 쪽에서는 오브젝트를 만들 때 사용할 클래스가 무엇인지 몰라도 됩니다. 인터페이스를 통해 접근하게 하면 실제 구현 클래스를 바꿔도 신경 쓸 일이 없습니다.

 

인터페이스 도입 후 클래스의 관계이면 UserDao는 자신이 사용한 클래스가 어떤 것인지 몰라도 됩니다. 단지 인터페이스를 통해 원하는 기능만 사용하기만 하면 됩니다.

 

인터페이스 정의

// UserDaoInterface.java
public interface UserDaoInterface {
    void saveUser(User user);
    User getUserById(int userId);
}

USerDao 인터페이스 정의

// UserDao.java
public class UserDao implements UserDaoInterface {
    @Override
    public void saveUser(User user) {
        // 사용자 정보를 저장하는 코드
    }

    @Override
    public User getUserById(int userId) {
        // 사용자 정보를 조회하는 코드
        return null;
    }
}

UserDao 클래스는 UserDaoInterface를 통해 기능을 사용할 수 있습니다. 실제로 UserDao 클래스가 어떤 클래스를 사용하는지는 UserDao 내부에서는 알 필요가 없습니다.  대신 인터페이스르 통해 기능을 호출하면 됩니다.

// Main.java
public class Main {
    public static void main(String[] args) {
        UserDaoInterface userDao = new UserDao(); // 인터페이스를 통해 객체 생성
        User user = new User("John Doe");
        userDao.saveUser(user);
        User retrievedUser = userDao.getUserById(1);
    }
}

 

위 코드에서는 UserDao 클래스를 UserDaoInterface를 통해 생성하고, 인터페이스의 메서드를 호출하여 기능을 사용하고 있습니다. UserDao클래스 내부에서는 사용하는 클래스에 대한 구체적인 정보를 알 필요가 없으며, 필요한 기능을 인터페이스를 통해 호출할 수 있습니다. 이렇게 하면 실제 구현 클래스를 변경해도 Main클래스나 다른 클래스에서는 영향을 받지 않고 동일한 인터페이스를 통해서 기능을 사용할 수 있습니다.

 

관계설정 책임 분리

UserDao클래스가 구현 클래스 간의 관계 설정을 독립적으로 다루지 못하는 문제를 해결하기 위해 다음과 같은 방법을 제안할 수 있습니다.

 

1. 의존성 주입

UserDao 클래스의 생성자를 수정하여 ConnectionMaker 인터페이스를 구현한 클래스의 인스턴스를 파라미터로 받는걸 의존성 주입이라고 합니다.

UserDao 클래스 내에서 직접 ConnectinoMaker 구현 클래스를 생성하거나 결정하는 코드를 제거합니다.

 

public class UserDao {
    private final ConnectionMaker connectionMaker;

    public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }

    // UserDao의 다른 메서드들은 connectionMaker를 사용하여 데이터베이스와 상호작용합니다.
}

 

2. 의존성 주입을 통한 동적 관계 설정

클라이언트 코드에서 UserDao를 생성할 때 적절한 ConnectionMaker 구현 클래싀 인스턴스를 생성하여 전달합니다.

이 방법을 통해 UserDao의 클라이언트가 UserDao와 ConnectionMaker 구현 클래스의 관계를 동적으로 결정할 수 있습니다.

public class Main {
    public static void main(String[] args) {
        ConnectionMaker connectionMaker = new MySQLConnectionMaker(); // 또는 다른 ConnectionMaker 구현 클래스
        UserDao userDao = new UserDao(connectionMaker);

        // userDao를 사용하여 데이터베이스 작업을 수행합니다.
    }
}

이러한 방식으로 UserDao의 클라이언트에서 UserDao와 ConnectionMaker의 관게를 결정하고, UserDao는 이를 실행에만 집중할 수 있게 되며 객체지향 프로그래밍 원칙중 하나인 단일 책임 원칙을 따릅니다.

 

원칙과 패턴

개방 패쇄 원칙(Open-Closed-Principle)

개방 패쇄 원칙은 소프트웨어의 유지보수성, 확장성, 재사용성을 높이기 위해 중요합니다. 개방- 패쇄 원칙을 따르는 설계를 하면 기존의 코드를 변경하지 않고 새로운 기능을 추가할 수 있어서 코드의 안정성과 확장성이 높아집니다.

 

Open

소프트웨어 엔티티는 확장에 대해 개방되어야 합니다. 즉 새로운 기능이 추가되거나 변경이 필요할 때 해당 엔티티의 동작을 수정하지 않고 확장할 수 있어야 합니다.

Close

소프트웨어 엔티티는 수정에 대해서는 폐쇄되어야 합니다. 즉 기존의 코드를 수정하지 않고도 새로운 기능을 추가하거나 기존 기능을 변경할 수 있어야 합니다.

 

높은 응집도

응집도가 높다는 것은 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 것으로 설명할 수 있습니다. 즉 변경이 일어날 때 모듈의 많은 부분이 함께 바뀐다면 응집도가 높다고 말할 수 있습니다. 

 

닞은 결합도

높은 응집도보다 더 민감한 원칙이며, 책임과 관심사가 다른 오브젝트 또는 모듈과 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직합니다. 느슨한 연결은 관게를 유지하는 데 꼭 필요한 최소한의 방법만 간접적이 형태로 제공하고, 나머지는 서로 독립적이고 알 필요도 없게 만들어 주는 것입니다. 결합도가 낮아지면 변화에 대응하는 속도도 빠르고, 구성도 깔끔해지며 확장에도 편리해 집니다.

 

전략 팬턴

전략 패턴은 디자인의 꽃이라고 불리며 다양하게 자수 사용되는 패턴입니다. 개방 패쇄 원칙의 실현에도 가장 잘 맞는 패턴입니다. 전략 패턴은 자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘(거창한 수학적 알고리즘이 아닌 독립적인 책임으로 분리가 가능한 기능)을 인터페이스를 통해 통쨰로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴입니다.

 

728x90

'Spring(Boot & FrameWork)' 카테고리의 다른 글

Enumerated  (0) 2024.03.28
초난감 DAO  (1) 2024.03.26
CRON 표현식  (0) 2024.02.08