재사용 코드가 왜 유익한 지에 대해 논의 할 필요가 거의 없습니다. 코드 재사용은 일반적으로 프로그램 개발을 더 빠르게 만들고 버그를 줄입니다. 코드 조각이 캡슐화되고 재사용되면 프로그램의 정확성을 보장하기 위해 매우 작은 코드를 확인해야합니다. 애플리케이션 내내 한 곳에서 데이터베이스 연결을 열고 닫으면 연결이 정상인지 확인하는 것이 훨씬 쉽습니다. 그러나 나는 당신이 이미이 모든 것을 알고 있다고 확신합니다.
재사용 코드에는 두 가지 유형이 있습니다.
첫 번째 유형은 기능 재사용이며 가장 일반적인 유형의 재사용입니다. 이것은 또한 대부분의 개발자에게 일종의 숙달입니다. 즉, 일부 작업을 수행하기위한 후속 지침 세트를 재사용하십시오.
두 번째 유형은 컨텍스트 재사용입니다. 즉, 다른 함수 또는 작업 코드가 동일한 컨텍스트 사이에 캡슐화되고 동일한 컨텍스트가 재사용 코드로 캡슐화됩니다 (여기서 컨텍스트는 일련의 동일한 작업 지침을 나타냅니다). 제어 역전에서 점점 인기를 얻고 있지만 일반적이지 않습니다. 또한 컨텍스트 재사용은 명시 적으로 설명되지 않으므로 기능 재사용과 같은 시스템에서 사용하지 않습니다. 이 기사를 읽은 후에 변경되기를 바랍니다.
기능 재사용
기능 재사용은 가장 일반적인 유형의 재사용입니다. 어떤 종류의 작업을 수행하는 일련의 지침을 재사용하는 것입니다. 다음 두 가지 방법은 데이터베이스에서 데이터를 읽는 것입니다.
공개 목록 readAllUsers () {연결 연결 = null; 문자열 SQL = "선택 *에서 사용자"; List Users = New ArrayList (); try {connection = openConnection (); preparedstatement statement = connection.preparestatement (SQL); resultSet result = state.executeQuery (); while (result.next ()) {// 코드 user = new user (); user.setName (result.getString ( "name")); user.setEmail (result.getString ( "이메일")); user.add (사용자); // end Reuse code} result.close (); statement.close (); 반환 사용자; } catch (sqlexception e) {// 지금은 무시} 마침내 {// 지금 무시}} public list readusersofstatus (문자열 상태) {Connection Connection = null; 문자열 sql = "select * where status =?"; List Users = New ArrayList (); try {connection = openConnection (); preparedstatement statement = connection.preparestatement (SQL); statement.setString (1, 상태); resultSet result = state.executeQuery (); while (result.next ()) {// 코드 user = new user (); user.setName (result.getString ( "name")); user.setEmail (result.getString ( "이메일")); user.add (사용자); // end Reuse code} result.close (); statement.close (); 반환 사용자; } catch (sqlexception e) {// 지금은 무시} 마침내 {// 지금 무시}}}숙련 된 개발자의 경우 재사용 가능한 코드를 곧 발견 할 수 있습니다. 위의 코드에서 "재사용 코드"가 주석을 달린 장소는 동일하므로 재사용을 캡슐화 할 수 있습니다. 사용자 레코드를 사용자 인스턴스로 읽는 작업입니다. 이러한 코드 라인은 예를 들어 자체 방법으로 캡슐화 할 수 있습니다.
// 동일한 작업을 readUser 메소드에 캡슐화 개인 사용자 readUser (resultSet result) 던지기 sqlexection {user user = new user (); user.setName (result.getString ( "name")); user.setEmail (result.getString ( "이메일")); user.add (사용자); 리턴 사용자; }이제 위의 두 가지 메소드에서 readUser () 메소드를 호출합니다 (다음 예제는 첫 번째 방법 만 보여줍니다).
공개 목록 readAllUsers () {연결 연결 = null; 문자열 SQL = "선택 *에서 사용자"; List Users = New ArrayList (); try {connection = openConnection (); preparedstatement statement = connection.preparestatement (SQL); resultSet result = state.executeQuery (); while (result.next ()) {user.add (readuser (result))} result.close (); statement.close (); 반환 사용자; } catch (sqlexception e) {// 지금은 무시} 마침내 {// 지금 무시}}}readUser () 메소드는 수정 자 개인을 사용하여 자체 클래스에서 숨겨 질 수 있습니다.
위의 것은 기능 재사용에 관한 것입니다. 기능적 재사용은 방법이나 클래스를 통해 특정 작업을 수행하여 재사용의 목적을 달성하는 일련의 지침을 캡슐화하는 것입니다.
매개 변수화 된 작업
때로는 일련의 운영을 재사용하고 싶지만 이러한 작업은 사용하는 곳마다 정확히 동일하지 않습니다. 예를 들어, readAllUsers () 및 readUsersofStatus () 메소드는 연결을 열고 문을 준비하고 실행하고 결과 세트를 검사합니다. 유일한 차이점은 readusersofStatus ()가 준비 상태에서 매개 변수를 설정해야한다는 것입니다. 모든 작업을 readuserList () 메소드로 캡슐화 할 수 있습니다. 아래 그림과 같이 :
개인 목록 readUserList (String SQL, String [] 매개 변수) {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, 매개 변수 [i]); } resultSet result = state.executeQuery (); while (result.next ()) {user.add (readuser (result))} result.close (); statement.close (); 반환 사용자; } catch (sqlexception e) {// 지금은 무시} 마침내 {// 지금 무시}}} 이제 readAllUsers() 및 readUsersOfStatus() 의 readUserList(...) 메소드를 호출하고 다른 작동 매개 변수를 제공합니다.
공개 목록 readAllusers () {return readuserList ( "선택 *에서 선택 *", 새 문자열 [] {});} 공개 목록 readUserswithStatus (문자열 상태) {return readuserList ( "select * from user", new String [] {status});}재사용 기능을 구현하고 사용하기 쉽도록 매개 변수화하는 다른 더 나은 방법을 찾을 수 있다고 생각합니다.
컨텍스트 재사용
컨텍스트 재사용은 기능 재사용과 약간 다릅니다. 컨텍스트 재사용은 일련의 지침을 재사용하는 것입니다.이 지침 간에는 항상 다양한 작업이 수행됩니다. 다시 말해, 다양한 행동 전후에 진술을 재사용합니다. 따라서 컨텍스트 재사용은 종종 제어 스타일 클래스의 역전으로 이어집니다. 컨텍스트 재사용은 예외 처리, 연결 및 트랜잭션 라이프 사이클 관리, 흐름 반복 및 종료 및 기타 많은 일반적인 운영 상황을 재사용하는 매우 효과적인 방법입니다.
입력 스트림으로 수행되는 두 가지 방법은 다음과 같습니다.
public void printstream (inputStream inputStream)은 ioException {if (inputStream == null) return; IoException Exception = NULL; try {int 문자 = inputStream.read (); while (character! = -1) {system.out.print ((char) 문자); // 다른 문자 = inputStream.Read (); }} 마침내 {try {inputStream.close (); } catch (ioexception e) {if (Exception == null) Throw e; }}} public String readStream (inputStream inputStream)은 ioException {StringBuffer buffer = new StringBuffer (); // 다른 if (inputStream == NULL) 리턴; IoException Exception = NULL; try {int 문자 = inputStream.read (); while (character! = -1) {buffer.append ((char) 문자); // 다른 문자 = inputStream.Read (); } return buffer.toString (); // 다른} 마침내 {try {inputStream.close (); } catch (ioexception e) {if (Exception == null) Throw e; }}}두 가지 방법은 흐름 작동과 다릅니다. 그러나 이러한 작업에 대한 맥락은 동일합니다. 컨텍스트 코드는 입력 스트림을 반복하고 닫습니다. 주석 마크 사용의 차이점 외에도 위의 코드는 컨텍스트 코드입니다.
위에서 볼 수 있듯이 컨텍스트에는 예외 처리가 포함되며 반복 후 스트림이 올바르게 닫히도록합니다. 이러한 오류 처리 및 리소스 릴리스 코드를 계속해서 작성하는 것은 번거롭고 오류가 발생하기 쉽습니다. JDBC 트랜잭션에서 오류 처리 및 올바른 연결 처리가 더 복잡합니다. 한 번 코드를 작성하고 어디서나 재사용하는 것이 더 쉽습니다.
다행히 컨텍스트를 캡슐화하는 방법은 간단합니다. 컨텍스트 클래스를 만들고 대중의 맥락을 그에 넣습니다. 컨텍스트를 사용하면 다른 작동 지침이 작동 인터페이스로 추상화 된 다음 각 작업이 클래스에서 작동 인터페이스를 구현하는 클래스에서 캡슐화됩니다 (여기서는 클래스 클래스라고 함). 작업 클래스의 인스턴스를 컨텍스트에만 삽입하면됩니다. 작업 클래스의 인스턴스를 컨텍스트 객체의 생성자에게 매개 변수로 전달하거나 컨텍스트의 특정 실행 방법에 매개 변수로서 조작 클래스의 인스턴스를 전달하여 수행 할 수 있습니다.
다음은 위의 예를 컨텍스트 및 운영 인터페이스로 분리하는 방법을 보여줍니다. StreamProcessor (Operation Interface)는 streamProcessorContext의 ProcessStream () 메소드로 매개 변수로 전달됩니다.
// 스트림 프로세싱 플러그인 인터페이스 공용 인터페이스 스트림 프로세서 {public void process (int input);} // 스트림 처리 컨텍스트 클래스 공개 클래스 스트림 프로세서 커넥트 {// 스트림 프로세서 작동 인터페이스를 인스턴스화하고 public void processStream (inputStream inputstream, streamProcessor)으로 제공됩니다. IoException Exception = NULL; try {int 문자 = inputStream.read (); while (character! = -1) {processor.process (문자); 문자 = inputStream.read (); }} 마침내 {try {inputStream.close (); } catch (ioexception e) {if (Exception == null) Throw e; 던지기 예외; }}}}이제 streamProcessorContext 클래스를 사용하여 다음 예제와 같은 스트림 컨텐츠를 인쇄 할 수 있습니다.
fileInputStream inputStream = new FileInputStream ( "myFile"); // 스트림 프로세서 인터페이스의 익명 서브 클래스 구현을 통한 작업의 예 새 스트림 프로세서 컨트리 텍스트 (). ProcessStream (inputStream, new void process (int input (int input) {System.out.print (char));또는 이와 같은 입력 스트림 컨텐츠를 읽고 문자 순서에 추가하십시오.
public class streamtoStringReader는 streamProcessor {private StringBuffer buffer = new StringBuffer (); public StringBuffer getBuffer () {return this.buffer; } public void process (int input) {this.buffer.append ((char) 입력); }} fileInputStream inputStream = new FileInputStream ( "myFile"); streamToStringReader reader = new StreamToStringReader (); new StreamProcessorContext (). ProcessStream (InputStream, Reader); // streame.reader.getBuffer ()에서 입력으로 무언가를 수행합니다.보시다시피, 다른 스트림 프로세서 인터페이스 구현을 삽입하여 스트림으로 무엇이든 수행하십시오. StreamProcessorContext가 완전히 구현되면, 당신은 탈수 된 스트림에 아무런 문제가 없을 것입니다.
컨텍스트 재사용은 매우 강력하며 스트림 처리 외부의 다른 많은 환경에서 사용할 수 있습니다. 명백한 사용 사례는 데이터베이스 연결 및 트랜잭션을 올바르게 처리하는 것입니다 ( open - process - commit()/rollback() - close() ). 다른 사용 사례로는 중요 섹션의 NIO 채널 처리 및 스레드 동기화 ( lock() - access shared resource - unlock() )입니다. 또한 API에서 확인 된 예외를 확인되지 않은 예외로 변환 할 수도 있습니다.
프로젝트에서 컨텍스트 재사용에 적합한 코드를 찾으면 다음 작업 모드를 찾으십시오.
그러한 패턴을 찾으면, 정기적 인 작업 전후에 컨텍스트 재사용을 달성 할 수 있습니다.
템플릿 메소드로서의 컨텍스트
때로는 컨텍스트에 여러 개의 플러그인 포인트를 갖기를 원합니다. 컨텍스트가 많은 작은 단계로 구성되고 컨텍스트의 각 단계를 사용자 정의 할 수 있으려면 컨텍스트를 템플릿 메소드로 구현할 수 있습니다. 템플릿 메소드는 GOF 설계 패턴입니다. 기본적으로 템플릿 메소드는 알고리즘 또는 프로토콜을 일련의 단계로 나눕니다. 템플릿 방법은 일반적으로 단일 기본 클래스로 구현되며 알고리즘 또는 프로토콜의 각 단계에 대한 메소드를 제공합니다. 모든 단계를 사용자 정의하려면 템플릿 메소드베이스 클래스를 확장하는 클래스를 작성하고 사용자 정의하려는 단계의 메소드를 무시하십시오.
다음 예제는 템플릿 메소드로 구현 된 JDBCContext입니다. 서브 클래스는 커스텀 동작을 제공하기 위해 연결의 개방 및 폐쇄를 무시할 수 있습니다. ProcessRecord (resultSet result) 메소드는 추상적이기 때문에 항상 재정의되어야합니다. 이 방법은 컨텍스트에 있지 않으며 JDBCContext를 사용하는 경우 다른 경우 다른 작업을 제공합니다. 이 예제는 완벽한 jdbccontext가 아닙니다. 컨텍스트를 구현할 때 템플릿 메소드를 사용하는 방법을 보여주는 데만 사용됩니다.
공개 초록 클래스 jdbccontext {dataSource dataSource = null; // 매개 변수가없는 생성자는 공개 JDBCContext () {} 공개 JDBCContext (DataSource DataSource) {this.datasource = DataSource; } protected connection openConnection ()는 sqlexception {return dataSource.getConnection (); } Protected Void CloseConnection (Connection Connection)은 sqlexception {connection.close (); } // processRecord (resultSet result) 메소드 보호 된 추상 프로세스 레코드 (resultSet result)는 sqlexception을 던졌습니다. public void execute (String SQL, Object [] 매개 변수)는 sqlexception {connection connection = null; preparedstatement 문 = null; resultSet result = null; try {connection = openConnection (); 명령문 = connection.preparestatement (SQL); for (int i = 0; i <parameters.length; i ++) {state.setObject (i, 매개 변수 [i]); } result = state.executeQuery (); while (result.next ()) {processRecord (result); }} 마침내 {if (result! = null) {try {result.close (); } catch (sqlexception e) { / * 무시 * /}} if (state! = null) {try {state.close (); } catch (sqlexception e) { / * 무시 * /}} if (state! = null) {try {state.close (); } catch (sqlexception e) { / * 무시 * /}} if (connection! = null) {closeConnection (Connection); }}}}이것은 jdbccontext를 확장하여 사용자 목록을 읽는 서브 클래스입니다.
Public Class Readusers는 jdbccontext {list users = new arraylist (); 공개 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 ( "이메일")); user.add (사용자); }}Readusers 클래스를 사용하는 방법은 다음과 같습니다.
readUsers readUsers = new ReadUsers (DataSource); readusers.Execute ( "select * from user", new Object [0]); list users = readusers.getUsers ();
ReadUsers 클래스가 연결 풀에서 연결을 가져 와서 사용 후 연결 풀에 다시 놓아야하는 경우 openConnection() 및 closeConnection(Connection connection) 메소드를 재정의하여 연결을 삽입 할 수 있습니다.
메소드를 통해 삽입 작업 코드를 다시 작성하는 방법에 유의하십시오. JDBCContext의 서브 클래스는 ProcessRecord 메소드를 무시하여 특수 레코드 처리를 제공합니다. StreamContext 예제에서, 조작 코드는 별도의 객체에 캡슐화되며 메소드 매개 변수로 제공됩니다. 작동 인터페이스 스트림 프로세서를 구현하는 객체는 ProcessStreamContext Class processStream(...) 메소드의 매개 변수로 전달됩니다.
컨텍스트를 구현할 때는 두 기술을 모두 사용할 수 있습니다. JDBCContext 클래스는 작동 인터페이스를 실행 메소드의 매개 변수로 구현하는 ConnectionOpener 및 ConnectionCloser 객체를 전달하거나 생성자의 매개 변수로 전달할 수 있습니다. 개인적으로, 나는 두 가지 이유로 별도의 작동 객체와 작동 인터페이스를 사용하는 것을 선호합니다. 먼저, 작동 코드를 더 쉽게 테스트 할 수 있습니다. 둘째, 여러 컨텍스트에서 작업 코드를 재사용 할 수 있습니다. 물론, 조작 코드는 코드의 여러 장소에서도 사용할 수 있지만 이는 이점 일뿐입니다. 결국, 우리는 단지 운영을 재사용하지 않고 상황을 재사용하려고 노력하고 있습니다.
결론
이제 코드를 재사용하는 두 가지 방법을 보았습니다. 고전적인 기능 재사용 및 덜 일반적인 컨텍스트 재사용. 바라건대 컨텍스트 재사용은 기능 재사용만큼 일반적입니다. 컨텍스트 재사용은 API의 기본 세부 사항 (예 : JDBC, IO 또는 NIO API 등)에서 코드를 추상화하는 매우 유용한 방법입니다. 특히 API에 관리 해야하는 리소스가 포함되어있는 경우 (on and then and 닫기, 받기 및 반환 등).
지속성/ORM API, Mr.Persister는 컨텍스트 재사용을 사용하여 자동 연결 및 트랜잭션 라이프 사이클 관리를 달성합니다. 이런 식으로 사용자는 연결을 올바르게 열거 나 닫거나 거래를 커밋하거나 롤백하는 것에 대해 걱정할 필요가 없습니다. Mr.Persister는 사용자가 작업을 삽입 할 수있는 컨텍스트를 제공합니다. 이러한 맥락은 개방, 폐쇄, 커밋 및 롤백을 담당합니다.
인기있는 스프링 프레임 워크에는 많은 컨텍스트 재사용이 포함되어 있습니다. 예를 들어 Springs JDBC 추상화. 스프링 개발자는이를 "제어 역전"으로 사용합니다. 스프링 프레임 워크에서 사용하는 유일한 제어 역전 유형은 아닙니다. Spring의 핵심 특징은 의존성 주입 Bean 공장 또는 "응용 컨텍스트"입니다. 의존성 주입은 또 다른 유형의 제어 역전입니다.
위는 편집자가 소개 한 Java 코드의 기능 및 컨텍스트 재사용입니다. 나는 그것이 당신에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!