자바 코드 재 활용 기능 및 컨 텍스트 재 활용

나 는 코드 를 왜 다시 사용 하 는 것 이 유리 한 지 거의 토론 할 필요 가 없다.코드 재 활용 은 일반적으로 프로그램 개발 을 더욱 빠 르 고 BUG 를 감소 시킨다.코드 가 봉인 되 고 다시 사용 되면 아주 적은 코드 만 검사 하면 프로그램의 정확성 을 확보 할 수 있다.전체 프로그램 에서 데이터베이스 연결 을 한 곳 에서 만 열 고 닫 으 면 연결 이 정상 적 인지 확인 하 는 것 이 훨씬 쉽다.그 건 다 알 고 있 을 거 라 고 확신 합 니 다.
두 가지 유형의 재 활용 코드 가 있 습 니 다.저 는 재 활용 유형 이 라 고 부 릅 니 다.
  • 기능 재 활용(Action Reuse)
  • 문맥 재 활용(Context Reuse)
  • 첫 번 째 유형 은 기능 중용 인 데 이것 은 가장 흔히 볼 수 있 는 중용 유형 이다.이것 도 대부분의 개발 자 들 이 장악 한 것 이다.즉,후속 명령 을 다시 사용 하여 어떤 조작 을 수행 하 는 것 이다.
    두 번 째 유형 은 상하 문 중용,즉 서로 다른 기능 이나 조작 코드 가 같은 상하 문 사이 에서 같은 상하 문 을 중용 코드 로 봉 하 는 것 이다.반전 을 통제 하 는 데 점점 인 기 를 끌 고 있 지만 흔 치 않다.그리고 상하 문 중용 은 명확 하 게 묘사 되 지 않 았 기 때문에 기능 중용 처럼 체계적으로 사용 되 지 않 았 다.나 는 네가 이 문장 을 다 본 후에 변화 가 있 기 를 바란다.
    기능 재 활용
    기능 재 활용 은 가장 흔히 볼 수 있 는 재 활용 유형 이다.그것 은 어떤 조작 명령 을 실행 하 는 재 활용 이다.다음 두 가지 방법 은 모두 데이터베이스 에서 데 이 터 를 읽 는 것 입 니 다.
    
    public List readAllUsers(){
      Connection connection = null;
      String sql = "select * from users";
      List users = new ArrayList();
      try{
        connection = openConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet result = statement.executeQuery();
        while(result.next()){
          //     
          User user = new User();
          user.setName (result.getString("name"));
          user.setEmail(result.getString("email"));
          users.add(user);
          // END     
        }
        result.close();
        statement.close();
        return users;
      }
      catch(SQLException e){
        //ignore for now
      }
      finally {
        //ignore for now
      }
    }
    public List readUsersOfStatus(String status){
      Connection connection = null;
      String sql = "select * from users where status = ?";
      List users = new ArrayList();
      try{
        connection = openConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, status);
        ResultSet result = statement.executeQuery();
        while(result.next()){
          //     
          User user = new User();
          user.setName (result.getString("name"));
          user.setEmail(result.getString("email"));
          users.add(user);
          // END     
        }
        result.close();
        statement.close();
        return users;
      }
      catch(SQLException e){
        //ignore for now
      }
      finally {
        //ignore for now
      }
    }
    경험 이 있 는 개발 자 들 에 게 는 재 활용 가능 한 코드 를 곧 발견 할 수 있 을 것 이다.위의 코드 에서'재 활용 코드'를 설명 하 는 곳 은 같 기 때문에 재 활용 할 수 있 습 니 다.이것 은 사용자 기록 을 사용자 인 스 턴 스 에 읽 는 작업 입 니 다.이 줄 코드 를 자신 들 의 방법 에 봉인 할 수 있 습 니 다.예 를 들 어:
    
    //          readUser    
    private User readUser(ResultSet result) throws SQLException {
      User user = new User();
      user.setName (result.getString("name"));
      user.setEmail(result.getString("email"));
      users.add(user);
      return user; 
    }
    현재 상기 두 가지 방법 에서 readUser()방법 을 호출 합 니 다.(아래 예제 에 서 는 첫 번 째 방법 만 표시 합 니 다)
    
    public List readAllUsers(){
      Connection connection = null;
      String sql = "select * from users";
      List users = new ArrayList();
      try{
        connection = openConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet result = statement.executeQuery();
        while(result.next()){
          users.add(readUser(result))
        }
        result.close();
        statement.close();
        return users;
      }
      catch(SQLException e){
        //ignore for now
      }
      finally {
        //ignore for now
      }
    }
    readUser()방법 도 자신의 클래스 에서 수정자 private 로 숨 길 수 있 습 니 다.
    이상 은 기능 재 활용 에 관 한 내용 입 니 다.기능 재 활용 은 특정한 조작 을 수행 하 는 명령 을 방법 이나 클래스 를 통 해 재 활용 하 는 목적 을 달성 하 는 것 이다.
    매개 변수 화 조작
    때때로,당신 은 한 조 의 조작 을 다시 사용 하 기 를 원 하지만,이 조작 들 은 사용 하 는 어느 곳 에서 도 완전히 같 지 않다.예 를 들 어 readAllUsers()와 readUsers OfStatus()방법 은 모두 연결 을 열 고 문 구 를 준비 하여 실행 하고 결과 집합 에 반복 적 으로 접근 하 는 것 이다.유일한 차이 점 은 readUsers OfStatus()가 Prepared Statement 에 인 자 를 설정 해 야 한 다 는 것 이다.우 리 는 모든 조작 을 readUserList()방법 으로 밀봉 할 수 있다.다음 과 같다.
    
    private List readUserList(String sql, String[] parameters){
      Connection connection = null;
      List users = new ArrayList();
      try{
        connection = openConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
        for (int i=0; i < parameters.length; i++){
          statement.setString(i, parameters[i]);
        }
        ResultSet result = statement.executeQuery();
        while(result.next()){
          users.add(readUser(result))
        }
        result.close();
        statement.close();
        return users;
      }
      catch(SQLException e){
        //ignore for now
      }
      finally {
        //ignore for now
      }
    }
    현재 우 리 는readAllUsers()readUsersOfStatus()에서readUserList(...)방법 을 호출 하고 서로 다른 조작 매개 변 수 를 지정 합 니 다.
    
    public List readAllUsers(){
      return readUserList("select * from users", new String[]{});
    }
    public List readUsersWithStatus(String status){
      return readUserList("select * from users", new String[]{status});
    }
    나 는 네가 다른 더 좋 은 방법 을 찾 아서 중용 기능 을 실현 하고 그들의 매개 변 수 를 더욱 잘 사용 할 수 있 을 것 이 라 고 믿는다.
    문맥 재 활용
    상하 문장의 중용 과 기능 중용 은 약간 다르다.상하 문 중용 은 일련의 지령 의 중용 으로 각종 서로 다른 조작 은 항상 이 지령 들 사이 에서 진행 된다.다양한 행동 전과 뒤의 문 구 를 반복 적 으로 사용 한 다 는 얘 기다.따라서 상하 문 중용 은 통상 적 으로 컨트롤 스타일 류 의 반전 을 초래 할 수 있다.상하 문 중용 은 이상 처리,연결 과 사무 생명주기 관리,흐름 교체 와 닫 기,그리고 많은 일반적인 상하 문 조작 에 매우 효과 적 인 방법 이다.
    여기 에는 두 가지 방법 이 있 는데 모두 InputStream 으로 만 든 것 이다.
    
    public void printStream(InputStream inputStream) throws IOException {
      if(inputStream == null) return;
      IOException exception = null;
      try{
        int character = inputStream.read();
        while(character != -1){
          System.out.print((char) character); //   
          character = inputStream.read();
        }
      }
      finally {
        try{
          inputStream.close();
        }
        catch (IOException e){
          if(exception == null) throw e;
        }
      }
    }
    public String readStream(InputStream inputStream) throws IOException {
      StringBuffer buffer = new StringBuffer(); //   
      if(inputStream == null) return;
      IOException exception = null;
      try{
        int character = inputStream.read();
        while(character != -1){
          buffer.append((char) character); //   
          character = inputStream.read();
        }
        return buffer.toString(); //   
      }
      finally {
        try{
          inputStream.close();
        }
        catch (IOException e){
          if(exception == null) throw e;
        }
      }
    }
    두 가지 방법 과 흐름 의 조작 은 다르다.그러나 이 를 둘 러 싼 문맥 은 같다.컨 텍스트 코드 가 교체 되 고 InputStream 을 닫 습 니 다.상기 코드 에 서 는 주석 표 시 를 사용 하 는 것 을 제외 하고 모두 문맥 코드 입 니 다.
    위 에서 보 듯 이 문맥 은 이상 처리 와 관련 되 고 교체 후 흐름 을 정확하게 닫 도록 보장 합 니 다.이러한 오류 처리 와 자원 방출 코드 를 한 번 또 한 번 작성 하 는 것 은 번 거 롭 고 실수 하기 쉽다.오류 처리 와 정확 한 연결 처 리 는 JDBC 업무 에서 더욱 복잡 하 다.코드 를 한 번 만 들 고 어디서 든 반복 해서 사용 하 는 것 이 쉬 울 것 입 니 다.
    다행히도 상하 문 을 봉인 하 는 방법 은 간단 하 다.컨 텍스트 클래스 를 만 들 고 공공 컨 텍스트 를 넣 습 니 다.상하 문 사용 에서 서로 다른 조작 지령 을 조작 인터페이스 에 추상 화한 다음 에 모든 조작 을 이 조작 인 터 페 이 스 를 실현 하 는 클래스 에 봉 하여(여기 서 조작 클래스 라 고 부른다)이 조작 클래스 의 실례 를 상하 문 에 삽입 하면 된다.조작 류 의 인 스 턴 스 를 매개 변수 로 문맥 대상 에 전달 하 는 구조 함수 나 조작 류 의 인 스 턴 스 를 매개 변수 로 문맥 에 전달 하 는 구체 적 인 집행 방법 으로 완성 할 수 있다.
    위 예제 들 을 문맥 과 조작 인터페이스 로 나 누 는 방법 을 보 여 준다.StreamProcessor(조작 인터페이스)를 매개 변수 로 StreamProcessor Context 에 전달 하 는 processStream()방법.
    
    //        
    public interface StreamProcessor {
      public void process(int input);
    }
    //        
    public class StreamProcessorContext{
      //   StreamProcessor             
      public void processStream(InputStream inputStream, StreamProcessor processor) throws IOException {
        if(inputStream == null) return;
        IOException exception = null;
        try{
          int character = inputStream.read();
          while(character != -1){
            processor.process(character);
            character = inputStream.read();
          }
        }
        finally {
          try{
            inputStream.close();
          }
          catch (IOException e){
            if(exception == null) throw e;
            throw exception;
          }
        }
      }
    }
    다음 예제 와 같이 StreamProcessor Context 류 를 사용 하여 스 트림 내용 을 출력 할 수 있 습 니 다.
    
    FileInputStream inputStream = new FileInputStream("myFile");
    //      StreamProcessor              
    new StreamProcessorContext()
    .processStream(inputStream, new StreamProcessor(){
      public void process(int input){
        System.out.print((char) input);
      }
    });
    또는 아래 와 같이 입력 흐름 내용 을 읽 고 문자 시퀀스 에 추가 합 니 다.
    
    public class StreamToStringReader implements StreamProcessor{
      private StringBuffer buffer = new StringBuffer();
      public StringBuffer getBuffer(){
        return this.buffer;
      }
      public void process(int input){
        this.buffer.append((char) input);
      }
    }
    FileInputStream inputStream = new FileInputStream("myFile");
    StreamToStringReader reader = new StreamToStringReader();
    new StreamProcessorContext().processStream(inputStream, reader);
    // do something with input from stream.
    reader.getBuffer();
    보시 다시 피 서로 다른 StreamProcessor 인 터 페 이 스 를 삽입 하여 대류 작업 을 수행 합 니 다.StreamProcessor Context 가 완전히 실현 되면 닫 히 지 않 은 흐름 에 대한 고민 은 영원히 없 을 것 입 니 다.
    상하 문장의 중용 은 매우 강해 서 흐름 처리 이외 의 많은 다른 환경 에서 사용 할 수 있다.하나의 뚜렷 한 용례 는 데이터베이스 연결 과 사 무 를 정확하게 처리 하 는 것 이다open - process - commit()/rollback() - close().다른 용례 는 NIO 채널 처리 와 임계 구역 의 스 레 드 동기 화lock() - access shared resource - unlock()이다.또한 API 의 검사 이상 을 검사 하지 않 은 이상 으로 변환 할 수 있 습 니 다.
    자신의 항목 에서 문맥 에 맞 는 코드 를 찾 을 때 다음 작업 모드 를 찾 으 십시오.
  • 일반적인 조작 전(genel action before)
  • 특수 조작(special action)
  • 일반적인 조작 후(genel action after)
  • 이러한 패턴 을 찾 았 을 때,전후의 일반적인 조작 은 상하 문 중용 을 실현 할 수 있다.
    문맥 을 템 플 릿 으로 하 는 방법
    가끔 은 문맥 에 여러 개의 플러그 인 점 이 있 기 를 바 랄 때 가 있 습 니 다.문맥 이 많은 작은 절차 로 구성 되 고 문맥 의 모든 절 차 를 사용자 정의 할 수 있 기 를 원한 다 면 문맥 을 템 플 릿 방법 으로 구현 할 수 있 습 니 다.템 플 릿 방법 은 GOF 디자인 모델 의 일종 이다.기본적으로 템 플 릿 방법 은 알고리즘 이나 협 의 를 일련의 절차 로 나눈다.하나의 템 플 릿 방법 은 보통 하나의 기본 클래스 로 이 루어 지고 알고리즘 이나 프로 토 콜 의 모든 단계 에 하나의 방법 을 제공 합 니 다.모든 절 차 를 사용자 정의 하려 면 확장 템 플 릿 방법 기본 클래스 를 만 들 고 사용자 정의 절 차 를 다시 쓰 는 방법 이 필요 합 니 다.
    아래 의 예 는 템 플 릿 방법 으로 이 루어 진 JdbcContext 입 니 다.하위 클래스 는 사용자 정의 행동 을 제공 하기 위해 연결 의 열 림 과 닫 기 를 다시 쓸 수 있 습 니 다.추상 적 이기 때문에 프로 세 스 레코드(ResultSet result)방법 을 처음부터 끝까지 다시 써 야 합 니 다.이 방법 은 상하 문 에 속 하지 않 는 동작 을 제공 합 니 다.JdbcContext 를 사용 하 는 상황 에 따라 동작 이 다 릅 니 다.이 예 는 완벽 한 JdbcContext 가 아니다.이것 은 상하 문 을 실현 할 때 템 플 릿 을 어떻게 사용 하 는 지 보 여 주 는 데 만 사 용 됩 니 다.
    
    public abstract class JdbcContext {
      DataSource dataSource = null;
      //                   DataSource      
      public JdbcContext() {
      }
      public JdbcContext(DataSource dataSource){
        this.dataSource = dataSource;
      }
      protected Connection openConnection() throws SQLException{
        return dataSource.getConnection();
      }
      protected void closeConnection(Connection connection) throws SQLException{
        connection.close();
      }
      //        processRecord(ResultSet result)   
      protected abstract processRecord(ResultSet result) throws SQLException ;
      public void execute(String sql, Object[] parameters) throws SQLException {
        Connection    connection = null;
        PreparedStatement statement = null;
        ResultSet     result   = null;
        try{
          connection = openConnection();
          statement = connection.prepareStatement(sql);
          for (int i=0; i < parameters.length; i++){
            statement.setObject(i, parameters[i]);
          }
          result = statement.executeQuery();
          while(result.next()){
            processRecord(result);
          }
        }
        finally {
          if(result   != null){
            try{
              result.close();
            }
            catch(SQLException e) {
              /* ignore */
            }
          }
          if(statement != null){
            try{
              statement.close();
            }
            catch(SQLException e) {
              /* ignore */
            }
          }
          if(connection != null){
            closeConnection(connection);
          }
        }
      }
    }
    사용자 목록 의 하위 클래스 를 읽 기 위해 jdbc Context 를 확장 합 니 다.
    
    public class ReadUsers extends JdbcContext{
      List users = new ArrayList();
      public ReadUsers(DataSource dataSource){
        super(dataSource);
      }
      public List getUsers() {
        return this.users;
      }
      protected void processRecord(ResultSet result){
        User user = new User();
        user.setName (result.getString("name"));
        user.setEmail(result.getString("email"));
        users.add(user);
      }
    }
    ReadUsers 클래스 를 어떻게 사용 하 는 지:
    
    ReadUsers readUsers = new ReadUsers(dataSource);
    readUsers.execute("select * from users", new Object[0]);
    List users = readUsers.getUsers();
    ReadUsers 클래스 가 연결 풀 에서 연결 을 가 져 오고 사용 한 후에 이 연결 풀 로 돌려 보 내야 한다 면 재 작성openConnection()closeConnection(Connection connection)방법 으로 연결 을 삽입 할 수 있 습 니 다.
    방법 을 통 해 조작 코드 를 다시 쓰 는 방법 에 주의 하 세 요.JdbcContext 의 하위 클래스 재 작성 processRecord 방법 은 특별한 기록 처 리 를 제공 합 니 다.StreamContext 예제 에서 조작 코드 는 단독 대상 에 봉 하여 방법 적 매개 변수 로 제공 합 니 다.조작 인터페이스 StreamProcessor 의 대상 을 매개 변수 로 StreamContext 류processStream(...)에 전달 하 는 방법 을 실현 합 니 다.
    상하 문 을 실시 할 때 너 는 이 두 가지 기술 을 사용 할 수 있다.JdbcContext 류 는 조작 인 터 페 이 스 를 실현 하 는 ConnectionOpener 와 ConnectionCloser 대상 을 매개 변수 로 execute 방법 이나 구조 함수 의 매개 변수 로 전달 할 수 있다.개인 적 으로 저 는 단독 조작 대상 과 조작 인 터 페 이 스 를 사용 하 는 것 을 더 좋아 합 니 다.그 이 유 는 두 가지 가 있 습 니 다.우선,조작 코드 가 단원 테스트 를 단독으로 진행 하기 쉽 도록 한다.그 다음 에 조작 코드 를 여러 문맥 에서 다시 사용 할 수 있 게 한다.물론 조작 코드 도 코드 의 여러 위치 에서 사용 할 수 있 지만 이것 은 장점 일 뿐이다.여기 서 우 리 는 문맥 을 다시 사용 하려 는 것 이지 다시 사용 하려 는 것 이 아니다.
    종결 어
    지금 너 는 이미 두 가지 다른 코드 를 다시 사용 하 는 방법 을 보 았 다.전형 적 인 기능 재 활용 과 흔 하지 않 은 문맥 재 활용.문맥 의 재 활용 이 기능 재 활용 처럼 보편화 되 기 를 바 랍 니 다.문맥 재 활용 은 API 의 바 텀 디 테 일(예 를 들 어 JDBC,IO 또는 NIO API 등)에서 코드 를 추상 화 할 수 있 는 매우 유용 한 방법 이다.특히 API 에 관리 해 야 할 자원(열 고 닫 기,가 져 오고 되 돌려 주 는 등)이 포함 되 어 있다 면.
    persistence/ORM API,Mr.Persister 는 상하 문 재사 용 을 이용 하여 자동 연결 과 사무 생명주기 관 리 를 실현 한다.이렇게 하면 사용 자 는 연결 을 정확하게 열거 나 닫 거나 제출 하거나 스크롤 백 하 는 것 을 영원히 걱정 하지 않 아 도 된다.Mr.Persister 는 사용자 가 작업 을 삽입 할 수 있 는 컨 텍스트 를 제공 합 니 다.이 상하 문 들 은 열 고 닫 고 제출 하고 스크롤 백 하 는 것 을 책임 집 니 다.
    유행 하 는 Spring 프레임 워 크 는 대량의 상하 문 중용 을 포함한다.예 를 들 어 Springs JDBC 추상.Spring 개발 자 들 은 컨 텍스트 를'반전 제어'로 재 활용 했다.이것 은 Spring 프레임 워 크 가 사용 하 는 유일한 반전 제어 유형 이 아니다.Spring 의 핵심 특성 은 bean 공장 이나'응용 프로그램 컨 텍스트'를 주입 하 는 것 입 니 다.의존 주입 은 또 다른 제어 반전 이다.
    위 에서 말 한 것 은 소 편 이 소개 한 자바 코드 재 활용 기능 과 문맥 재 활용 입 니 다.여러분 께 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

    좋은 웹페이지 즐겨찾기