"인터페이스 코드와 기능 코드를 분리하는 방법(Delphi/VCL 기반)"을 읽은 후 누군가 서버 측 클래스의 오류를 처리하는 방법에 대한 질문을 언급했습니다.
함수 기반 구조에서는 일반적으로 함수 반환 값을 사용하여 함수가 성공적으로 실행되었는지 여부를 나타내고 오류 유형과 같은 정보를 제공합니다. 따라서 다음과 같은 형식의 코드가 있습니다.
RetVal := SomeFunctionToOpenFile();
RetVal = E_SUCCESSED이면
...
그렇지 않은 경우 RetVal = E_FILENOTFOUND이면
...
그렇지 않은 경우 RetVal = E_FILEFORMATERR이면
...
그렇지 않으면
...
오류 코드를 반환하는 메서드를 사용하는 것은 매우 일반적이지만 이러한 메서드를 사용하는 데에는 두 가지 문제가 있습니다.
1. 길고 복잡한 분기 구조(많은 수의 if 또는 Case 문)를 생성하여 제어 프로세스를 복잡하게 만듭니다.
2. 처리되지 않은 오류가 있을 수 있습니다. (함수 호출자가 반환 값을 결정하지 않는 경우)
예외는 오류 처리를 위한 객체 지향 솔루션입니다. 오류를 보고할 수 있지만 알아야 할 것은 오류 때문에 예외가 발생하는 것이 아니라 단순히 raise를 사용했기 때문에 예외가 발생한다는 것입니다.
오브젝트 파스칼에서는 제기된 예약어가 예외를 발생시키는 데 사용됩니다. 언제든지(오류가 발생하지 않더라도) raise를 사용하면 예외가 발생합니다.
예외로 인해 예외가 발생한 지점에서 코드가 즉시 반환될 수 있으므로 아래의 민감한 코드가 실행되지 않도록 보호할 수 있습니다. 예외를 통해 함수에서 반환하는 것과 예외를 발생시키는 함수 자체에 대해 정상적으로 함수에서 반환(함수 끝까지 실행 또는 Exit 실행)하는 것에는 차이가 없습니다. 차이점은 호출자의 끝에서 예외를 통해 반환된 후 호출자의 try...out 블록(존재하는 경우)에 의해 실행 권한이 캡처된다는 것입니다. 호출자에 try...out 블록이 없는 경우 후속 문은 계속 실행되지 않지만 예외를 처리할 수 있는 try...out 블록이 발견될 때까지 상위 수준 호출자로 반환됩니다. 예외가 처리된 후에는 try...out 블록 뒤의 문이 계속 실행되고 제어는 예외를 처리하는 계층에 남습니다. 예외 처리기가 예외 처리가 충분히 완료되지 않았다고 판단하면 처리를 계속하려면 상위 수준 호출자가 필요하며 예외를 다시 발생시키고(간단한 raise; 사용) 상위 수준 호출자에게 제어를 전달할 수 있습니다. .
사전 설정된 try...out 블록이 전혀 없는 경우 전체 프로그램을 캡슐화하는 VCL의 가장 바깥쪽 try...out 블록에 의해 최종 예외가 포착됩니다.
따라서 처리되지 않은 예외가 없습니다. 즉, 처리되지 않은 오류가 없습니다(오류와 예외가 동일하지 않더라도). 이는 오류 코드를 반환하는 메서드를 사용하는 것보다 예외 메커니즘이 갖는 장점이기도 합니다. 또한 예외가 발생한 후에는 제어 프로세스의 방향이 매우 명확하여 프로세스가 제어를 잃지 않게 됩니다.
예외가 어떻게 작동하는지에 대한 예를 제공하기 위해 특정 형식의 파일을 열고 싶다고 가정해 보겠습니다.
먼저 두 개의 예외 클래스를 정의합니다(Exception에서 상속됨).
EFileNotFound = 클래스(예외);
EFileFormatErr = 클래스(예외);
Form1에 버튼이 있고 버튼을 누르면 파일이 열린다고 가정합니다.
PROcedure TForm1.Button1Click(Sender: TObject);
시작하다
노력하다
파일열기();
제외하고
EFileNotFound에서 수행
ShowMessage('죄송합니다. 파일을 찾을 수 없습니다.');
onEFileFormatErr do
ShowMessage('죄송합니다. 원하는 파일이 아닙니다.');
E:예외 수행
ShowMessage(E.메시지);
끝;
끝;
그리고 파일을 여는 기능은 다음과 같습니다.
프로시저 ToOpenFile;
varRetVal:정수;
시작하다
//파일을 열 코드
RetVal := -1; //열기 실패
RetVal = 0이면 //성공
출구
그렇지 않으면 RetVal = -1이면
EFileNotFound.Create('파일을 찾을 수 없음') 발생
그렇지 않으면 RetVal = -2이면
EFileFormatErr.Create('파일 형식 오류') 발생
else //다른 오류
Exception.Create('알 수 없는 오류');
끝;
프로그램에서 TForm1.Button1Click은 ToOpenFile을 호출하고 ToOpenFile에서 발생할 수 있는 예외 처리를 제외하고 사전 설정을 시도합니다. 물론 TForm1.Button1Click의 예외 처리 코드도 단순화할 수 있습니다.
절차 TForm1.Button1Click(Sender: TObject);
시작하다
노력하다
파일열기();
제외하고
ShowMessage('파일 열기 실패');
끝;
끝;
예외를 사용하면 오류 코드를 반환하는 메서드를 사용할 때 발생하는 문제가 해결됩니다. 물론 예외를 사용하는 데 비용이 들지 않는 것은 아닙니다. 예외는 프로그램의 부담을 증가시키므로 예외를 남용하는 것은 바람직하지 않습니다. 몇 번의 try...exc를 작성하는 것과 수천 번의 try...exc를 작성하는 것에는 큰 차이가 있습니다. Charlie Calverts는 다음과 같이 말했습니다. "유용해 보일 때는 try...out 블록을 사용해야 합니다. 하지만 이 기술에 너무 흥분하지 마십시오."
또한, 오브젝트 파스칼은 독특한 try...finally 구조를 도입했습니다. 앞서 예외를 통해 함수에서 복귀하는 것과 정상적으로 함수에서 복귀하는 것에는 차이가 없다고 말씀드렸습니다. 따라서 함수의 스택에 있는 로컬 개체는 자동으로 해제되지만 힙에 있는 개체는 그렇지 않습니다. 그러나 오브젝트 파스칼의 개체 모델은 스택이 아닌 힙에 존재하는 참조를 기반으로 합니다. 따라서 예외를 통해 함수에서 반환되기 전에 일부 로컬 개체 리소스를 정리해야 하는 경우가 있습니다. try...드디어 이 문제를 해결했습니다.
위의 ToOpenFile 코드를 다시 작성했습니다. 이번에는 ToOpenFile 프로세스 중에 일부 리소스를 사용하고, 예외가 발생한 후(또는 발생하지 않은 후) 함수에서 반환되기 전에 이러한 리소스를 해제했습니다.
프로시저 ToOpenFile;
varRetVal: 정수;
스트림: TStream;
시작하다
//파일을 열 코드
스트림 := TStream.Create;
RetVal := -1; //열기 실패
노력하다
RetVal = 0이면 //성공
출구
그렇지 않으면 RetVal = -1이면
EFileNotFound.Create('파일을 찾을 수 없음') 발생
그렇지 않으면 RetVal = -2이면
EFileFormatErr.Create('파일 형식 오류') 발생
else //다른 오류
Exception.Create('알 수 없는 오류');
마지막으로
스트림.무료;
끝;
끝;
위의 코드를 단계별로 살펴보면 RetVal의 값이 0인 경우에도 Exit를 실행한 후에도 최종적으로 코드가 계속 실행된 후 함수에서 반환되는 것을 알 수 있습니다. 이는 로컬 리소스의 올바른 릴리스를 보장합니다.
try...out과 try...finally의 목적과 사용 시나리오가 다르기 때문에 많은 초보자들이 이를 혼동합니다. 다음은 작성자의 개인적인 지식입니다. try...Exception은 일반적으로 호출자가 호출된 함수에서 발생하는 예외를 캡처하고 처리하는 데 사용됩니다. 그리고 try...finally는 일반적으로 일부 리소스 정리 작업을 수행하기 위해 예외를 발생시키는 함수에 사용됩니다.
객체 지향 프로그래밍은 "예외"라는 오류 처리 솔루션을 제공합니다. 현명하게 사용하면 작업에 도움이 되고 작성하는 코드의 품질을 크게 향상시킬 수 있습니다.
니크로소프트 ([email protected]) 2001.7.25
원본 출처: Sunistudio 문서 (http://www.sunistudio.com/asp/sunidoc.asp)