SPRING/Spring Basic

[스프링] 관심사의 확장 ( 추상클래스 )

IT록흐 2021. 7. 21. 15:49
반응형

 

 

[ 스프링 ] 관심사의 분리 ( DAO )

스프링 프레임워크를 사용하기 위한 기본 개념을 하나씩 정리해볼까 한다. ▷ 분리와 확장 분리와 확장을 고려한 설계는 미래를 대비한다. 프로그램을 만들 때는 '분리'와 '확장'을 고려해야한

lordofkangs.tistory.com

 

 

지난 포스팅에서

관심사의 분리에 대해서 알아보았다.

 

코드는 '관심사'가 있다.

 

관심사 별로 분리해줘야

유지보수가 용이하다.

 

관심사 분리

 

지난 포스팅에서

DAO 객체의 코드를

관심사 별로 분리하였다.

 

 

세부적으로 들어가면 

더 많은 관심사로 나눌 수 있지만 

크게 세 가지로 나눌 수 있다.

 

1. DB접근 객체 생성 

2. 레코드 삽입

3. 레코드 추출 

 

세 가지 관심사를 메소드 별로 '분리'하였다.

 

public class UserDao {
	
    	//DB접근 객체 생성
	public Connection getConnection() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			
			String url = "jdbc:mysql://localhost:3306/SpringProject";
			String id = "root";
			String pw = "111111";
			
			Connection c = DriverManager.getConnection(url, id, pw);
			
			return c;
			
		} catch (ClassNotFoundException e) {
			System.out.println("클래스 발견 못함");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
		}
		return null;
	}
    
	 // 레코드 삽입
	public int add(User user) throws SQLException {
		
			Connection c = getConnection();
			
			String sql = "INSERT INTO USER(UserId,Name,Password) VALUES(?,?,?)";
			PreparedStatement ps = c.prepareStatement(sql);
			
			ps.setString(1, user.getId());
			ps.setString(2, user.getName());
			ps.setString(3, user.getPassword());
			
			int result = ps.executeUpdate();
			ps.close();
			c.close();
			
			return result;	
	}
    
	 //레코드 추출
	public User get(String UserId) throws SQLException {
		
			Connection c = getConnection();
			
			String sql = "SELECT * FROM USER WHERE UserId = ?";
			PreparedStatement ps = c.prepareStatement(sql);
			
			ps.setString(1,UserId);
			
			ResultSet rs = ps.executeQuery();
			User user = new User();
			
			while(rs.next()) {
				
				user.setId(rs.getString("UserId"));
				user.setName(rs.getString("Name"));
				user.setPassword(rs.getString("Password"));
				
			}
			rs.close();
			ps.close();
			c.close();
			
			return user;
	}
}

 

 

 

여기까지가 

지난 포스팅의 내용이다.

 

관심사의 확장 ( 추상 클래스 )

 

메소드를 관심사 별로 분리하면 변화에 대응할 수 있는 코드가 된다. 그러나 확장성이 떨어진다.

 

A사는 DBMS로 Oracle을 쓰고 B사는 DBMS로 MySQL을 쓴다고 가정하자. 그러나 UseDao 클래스의 코드는 한 가지 DB만 전담할 수 있다. 만약 다른 DBMS를 사용하려면 코드를 고쳐야한다. 이는 유지보수성을 떨어뜨린다. 그러므로 '분리'도 중요하지만 '확장'도 중요하다. 확장성을 고려한 코드를 짜야한다.

 

우리는 확장성을 위해 '추상클래스'를 사용할 것이다.

 

 

public abstract class UserDao { // 추상 클래스 
	
	public abstract Connection getConnection(); // 확장을 원하는 메소드를 추상메소드로 선언
	
	public int add(User user) throws SQLException {
			//생략...
	}
	
	public User get(String UserId) throws SQLException {
			// 생략....
	}

}

 

 

이와 같이, 확장을 원하는 메소드를 추상메소드로 선언하면 추상클래스를 상속한 구현 클래스는 추상 메소드를 '반드시' 정의해야 한다. 

 

1. 구현 클래스 ( A사 )

 

public class AConnection extends UserDao { // 추상클래스 상속

	@Override // 추상메소드 재정의
	public Connection getConnection() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/SpringProject";
			String id = "ACompany";
			String pw = "111111";
			
			Connection c = DriverManager.getConnection(url, id, pw);
			System.out.println("A사 커넥션 접근 객체 생성");
			return c;
			
		} catch (ClassNotFoundException e) {
			System.out.println("클래스 발견 못함");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
		}
		return null;
	}
}

 

 

2. 구현 클래스 ( B사 )

 

public class BConnection extends UserDao { // 추상클래스 상속
	@Override // 추상메소드 재정의
	public Connection getConnection() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			
			String url = "jdbc:mysql://localhost:3306/SpringProject";
			String id = "BCompany";
			String pw = "111111";
			
			Connection c = DriverManager.getConnection(url, id, pw);
			System.out.println("B사 커넥션 접근 객체 생성");
			return c;
			
		} catch (ClassNotFoundException e) {
			System.out.println("클래스 발견 못함");
		} catch (SQLException e) {
			System.out.println("DB 접속 실패");
		}
		return null;
	}
}

 

 

이로써, getConnection() 메소드는 A사 와 B사 따로 독립적인 코드를 갖게 되었다. 그러므로 A사와 B사의 DBMS에 맞게 getConnection() 메소드를 새롭게 재정의(Overriding)하면 된다. '분리'와 '확장'을 동시에 이룬 것이다. 

 

그러나 단점이 하나 있다.

 

JAVA에서 상속(extends)은 '다중상속'을 허용하지 않는다.

 

A사와 B사는 자사의 DBMS에 맞는 DB 접근 객체 생성이라는 '관심사'를 위해 UserDao 클래스를 상속했다. 이는 한 가지 관심사를 위해,  3가지 이상의 다른 관삼사를 가진 클래스를 상속한 꼴이 된다. 한 가지 관심사를 위해 다른 관심사가 희생된 것이다. 

 

UserDao 클래스와 AConnection 클래스는 추상클래스 - 구현 클래스 관계이지만 서로 성격과 용도가 다르다. 그러므로 분리와 확장을 위한 상속은 오히려 독이 될 수 있다. 그럼 이같은 문제를 해결하려면 어떻게 할까? 다음 포스팅에서 정리하겠다.

 

 

반응형