멋사 Backend 26일차 🦁 (CodeLion 강의)

신재원·2023년 5월 24일

🟨 조코딩님의 CodeLion 강의

👀 실검에 오르는 세렝게티 동물 테스트 만들기

  • html / css / javascript 를 이용하여 프로젝트를 진행하였고, Netlify 를 통해 배포 하는 방법을 배웠으며, 배너 광고를 세팅하는 방법을 배웠습니다.

🍀 Spring

Dao의 관심사 분리

  • add() 메소드 (Db에 insert)

public class UserDao {

    public void add(User user) throws ClassNotFoundException,SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");

        PreparedStatement ps = c.prepareStatement
                ("insert into users(id, name, password) values(?, ?, ?)");

        ps.setString(1, user.getId());
        ps.setString(2, user.getName());
        ps.setString(3, user.getPassword());

        ps.executeUpdate();
        ps.close();
        c.close();
    }
}
  • get() 메소드 (Db에 select)

public User get(String id) throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");

        // 값을 뽑아오는 쿼리문 작성
        PreparedStatement ps = c.prepareStatement
                ("select * from users where id = ?");

        ps.setString(1, id);

        ResultSet rs = ps.executeQuery();
        rs.next();

        User user = new User();
        user.setId(rs.getString("id"));
        user.setName(rs.getString("name"));
        user.setPassword(rs.getString("password"));
        return user;
    }
}

문제점 ❓

❗❗ 아래 코드가 중복이 되는것을 확인할수있습니다.

   Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");
// db url 주소 : 저는 AWS Ec2 퍼블릭 Dns 주소를 적었습니다.

또 단순히 Db의 password가 변경되었을경우 관계를 맺고있는 코드의 password를 일일이 다 수정해줘야되는 불상사가 발생 하게 됩니다.

👀👀 리펙토링 과정

1차 리펙토링

  • 중복되는 코드를 분리하여 메소드로 추출하여 호출하여 사용할수있게 만들수있습니다.
private Connection getConnection() throws ClassNotFoundException, 
	SQLException 
    {
       Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");
        return c;
    }
  • Connection을 return 타입으로 가지는 메소드를 만들어 중복되는 코드를 분리하였습니다.

📌 getConnection() 을 호출하여 사용할수있습니다.

 public void add(User user) throws ClassNotFoundException, SQLException {
        // 호출하여 사용
        Connection c = getConnection();
}

문제점 ❓

Connection의 생명주기등 문제가 있다고 합니다.

2차 리펙토링

  • 추상 클래스의 상속을 통해 해결할수도있지만 현업에서는 추상클래스를 거의 쓰지않습니다.

  • (자바에서는 다중상속을 지원하지 않기 때문)
    그러므로 상속을 지양합니다.

3차 리펙토링

  • 새로운 클래스를 하나 만들자 !
public class SimpleConnectionMaker {
    public Connection makeConnection() throws ClassNotFoundException,
    	SQLException 
        {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");
        return c;
    }
}
  • new 연산자를 통해 객체 생성 방식으로 의존성을 해결할수 있습니다.
  private SimpleConnectionMaker simpleconnectionMaker;

    public UserDao() {
        this.simpleconnectionMaker = new simpleconnectionMaker();
    }

    public void add(User user) throws ClassNotFoundException,SQLException {
    	// SimpleConnectionMaker 클래스에 makeConnection 이라는 
		// 메소드가 구현 되어있어야합니다.
        
        Connection c = simpleconnectionMaker.makeConnection();
    }

문제점 ❓

  1. 구체적인 클래스에 직접 하기때문에 강결합이 되며, 결합이 강하게 되면 유연성과 재사용성이 떨어집니다.
  2. 테스트 코드의 작성에 어려움이 있습니다.

4차 (궁극적) 리펙토링

  • 인터페이스를 사용합니다
    ( 인터페이스란 틀 / 역할을 정의해 놓은것입니다 )
    (다중 상속이 가능합니다)

📍 Connection 인터페이스 구현

public interface ConnectionMaker {
    Connection makeConnection() throws ClassNotFoundException,SQLException;
}

📍 Connection을 implement한 구현 클래스

public class NConnectionMaker implements ConnectionMaker{

    @Override
    public Connection makeConnection() throws ClassNotFoundException, 
    	SQLException 
    {
         Class.forName("com.mysql.cj.jdbc.Driver");
        Connection c = DriverManager.getConnection
			("db url주소", "해당 Db의 Username", "해당 Db의 password");
        return c;
    }
}

📍 생성자를 통한 의존성 주입 (DI)

private ConnectionMaker connectionMaker;

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

생성자 의존성 주입의 장점 ❓

✔ 3차 리펙토링에서는 구체적인 클래스와 관계를 맺음으로써 결합의 강도가 강 강했습니다.

  • 생성자 의존성 주입 (4차 리펙토링)에서는 직접적인 클래스와 관계를 맺지않고, 인터페이스를 통한 관계임으로 강도가 느슨해진다고 할수있습니다.
  • 결합이 느슨해짐으로써 재사용성과 확장, 테스트 코드의 작성이 수월해집니다.

결론 : 생성자 의존성 주입을 사용하자

0개의 댓글