본문 바로가기
IT/Spring

토비 스프링 - 템플릿

by 봉즙 2019. 10. 20.

개방 폐쇄 원칙(OCP) : 객체 지향 설계의 핵심 원칙이며, 코드에서 어떤 부분은 변경을 통해 그 기능이 다양해지고 확정하려는 성질이 잇고, 어떤 부분은 고정되어 있고 변하지 않으려는 성질이 있음을 말한다.

 

템플릿 : 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로 독립시켜서 효과적으로 활용할 수 있는 방법.

 

리소스 반환과 close()

Connection이나 PreparedStatement에는 close() 메서드가 존재하며, 만들어진 것을 종료하는 의미보다는 리소스를 반환한다는 의미로 주로 사용된다. Connection이나 PreparedStatement는 보통 pool 방식으로 운영되며, 미리 정해진 풀 안에 제한된 수의 리소스를 만들어 두고 필요할 때 이를 할당하고 반환하면 다시 풀에 넣는 방식으로 운영 됩니다. 요청이 많은 서버 환경에서는 매번 새로운 리소스를 생성하는 대신 풀에 미리 만들어둔 리소스를 돌려가며 사용하는 편이 훨씬 유리하다. 대신 사용한 리소스에 대해 빠르게 반환하지 않는다면 풀에 있는 리소스는 고갈되고 문제가 발생하게 된다. close()는 이를 풀로 다시 돌려주는 역할을 한다.

 

public void delteAll() throws SQLException {
	Connecton c = null;
    PreparedStatement ps = null;
    
    try { //예외가 발생할 가능성이 있는 코드를 모두 try블럭으로 묶어 준다.
    	c = dataSource.getConnection();
        ps = c.prepareStatement("delete from users");
        ps.executeUpdate();
    } catch (SQLException e) { //예외가 발생 했을 때 부가적인 작업을 해줄 수 있도록 catch 블록을 둔다.
    							//아직은 예외를 다시 메소드 밖으로 던지는 것 밖에 없다.
    	throw e;
    } finally {
    	if (ps != null) {
        	try{
            	ps.close();
            } catch(SQLExeption e) { //ps.close()메소드에서도 SQLException이 발생할 수 있기 때문에 이를 잡아줘야 한다.
            						 //그렇지 않으면 Connection을 close() 하지 못하고 메소드를 빠져나갈 수 있다.
            }
    }
    if (c != null) {
    	try {
        	c.close(); //Connection 반환
        }
        }
   }
   }
   }

try 블록으로 진입햇다면 반드시 Connection이나 PreparedStatement의 close()를 호출해 가져온 리소스를 반환해야 한다. 그런데 문제는 예외가 어느 시점에서 나는 가에 따라 Connection과 PreparedStatement 중 어떤 것의 close() 메서드를 호출해야 할지가 달라진다는 점이다. 만약 getConnection() 에서 DB 커넥션을 가져오다 일시적인 DB 서버 문제나 , 네트워크 문제 또는 그 밖의 예외상황 때문에 예외가 발생했다면 ps와 c도 null 상태이기에 null 체크를 해주어야 한다.

 

템플릿 메소드 패턴 : 상속을 통해 기능을 확장해서 사용하는 부분, 변하지 않는 부분은 슈퍼클래스에 두고 변하는 부분은 추상메소드로 정의해둬서 서브클래스에서 오버라이드하여 새롭게 정의해서 쓰도록 하는 것이다.
 하지만 템플릿 메소드 패턴으로의 접근은 제한이 많다. 가장 큰 문제는 DAO 로직마다 상속을 통해 새로운 클래스를 마들어야 한다는 점이다. 만약 이 방식을 사용한다면 단점으로 메소드가 4개인 경우 4개의 서브클래스를 만들어 사용해야한다. 또한 확장 구조가 이미 클래스를 설게하는 시점에서 고정되어 버린다.

 

전략 패턴 : 개방 폐쇄의 원칙 (OCP)를 잘 지키는 구조이면서도 템플릿 메소드 패턴보다 유연하고 확정성이 뛰어나다. 오브젝트를 아예 둘로 분리하고 클래스 레벨에서는 인터페이스를 통해서만 의존하도록 만드는 전략 패턴이다.

마이크로 DI : DI는 다양한 형태로 적용할 수 있다. DI의 중요한 개념은 제 3자의 도움을 통해 두 오브젝트 사이의 유연한 관계가 절정되도록 만드는 것이다. 
일반적으로 DI는 의존관계에 있는 두 개의 오브젝트와 이 관계를 다이나믹하게 설정해주는 오브젝트 팩토리(DI 컨테이너), 그리고 이를 사용하는 클라이언트라는4개의 오브젝트 사이에서 일어난다. 하지만 전략패턴 구조를 따라 클라이언트가 오브젝트 팩토리의 책임을 함께 지고 있을 수도 있다. 또한 클라이언트와 전략(의존 오브젝트)이 결합 될 수도 있다. 클라이언트와 DI관계에 있는 두 개의 오브젝트가 모두 하나의 클래스 안에 담길 수도 있다. 이러한 경우 DI가 매우 작은 단위의 코드와 메소드 사이에서 일어나기도 한다. 이렇게 DI의 장점을 단순화 해서 IoC컨테이너의 도움 없이 코드 내에서 적용한 경우을 말한다.

 

중첩 클래스의 종류 : 다른 클래스 내부에 정의도는 클래스, 독립적으로 오브젝트로 만들어질 수 있는 스태틱 클래스와 자신이 정의된 크래스의 오브젝트 안에서만 만들어 질수 있는 내부 클래스로 구분된다. 내부클래스는 다시 scope에 따라 세가지로 구분된다. 멤버 필드처럼 오브젝트 레벨에 정의되는 멤버 내부클래스와 메소드 레벨에 정의되는 로컬 클래스, 그리고 이름을 갖지 않는 익명 내부 클래스다. 익명 내부 클래스의 범위는 선언된 위치에 따라서 다르다.

 

로컬 클래스 장점 : 로컬 클래스는 클래스가 내부 클래스이기 때문에 자신이 선언된 곳의 정보에 접근 할 수 있다. 내부메소드는 자신이 정의된 메소드이 로컬 변수에 직접 접근 할 수 있다. 내부 ㅡㄹ래스에서 외부의 변수를 사용할 때는 외부 변수는 반드시 final로 선언해줘야한다.

 

익명 내부 클래스 : 이름을 갖지 않는 클래스, 언언과 오브젝트 생성이 결합된 형태로 만들어지며, 상속할 클래스나 구현할 인터페이스를 생성자 대신 사용하여 만들어 사용한다. 클래스를 재사용할 필요가 없고 구현한 인터페이스 타입만으로 사용할 경우에 유용하다.

new 인터페이스이름() { 클래스 본문 };

 

public void deleteAll() throw SQLException {
	jdbcContextWithStatementStrategy {
      new StatementsStrategy() { //익명 내부 클래스는 구현하는 인터페이스를 생성자처럼 이용해서 오브젝트를 만든다.
        public PreparedStatement makePreparedStatement(Connection C)
          throws SQLException {
          return c.prepareStatement("delete from user");
      }
    }
  };
}

'IT > Spring' 카테고리의 다른 글

토비 스프링 - 예외  (0) 2019.10.28
토비 스프링 - 템플릿 / 콜백  (0) 2019.10.23
토비 스프링 - 학습 테스트, 버그 테스트  (0) 2019.10.20
토비 스프링 - @Autowired  (0) 2019.10.19
토비 스프링 - 테스트  (0) 2019.10.19

댓글