본문 바로가기
Delphi/문법

객체지향 언어로서의 오브젝트 파스칼 3편

by MonoSoft 2021. 6. 8.
728x90
반응형

객체지향 언어로서의 오브젝트 파스칼 3편

 

■ 메소드와 생성자(constructor), 파괴자(destructor)의 추가

이제 TPerson 클래스에 몇가지 메소드를 추가해서 

조금은 쓸모가 있는 클래스로 만들어 보자. 

 

현재 가지고 있는 Name 필드는 그대로 두고,

ID 필드 대신, 주민등록번호를 저장할 수 있는 

RegID 필드를 만들자. 

 

이때 필드 임을 나타내기 위해

각 필드의 앞에 접두어로 ‘F’를 붙이도록 한다. 

 

그리고, 주민등록번호 필드 값을 가지고

이 값이 유효한지 알아보는

IsValid 함수와 나이와 성별을 알 수 있는

GetAge, GetSex 라는 함수를 추가한다.

 

또한, 이 클래스의 객체가 생성될 때 값을 초기화 시키기 위해 

생성자를 추가하자. 생성자(constructor)는 특별한 형태의 프로시저로, 

 

이것을 클래스에 적용하면 자동적으로

그 클래스의 객체를 위해 메모리를 할당하게 되며, 

초기화 작업을 지정할 수 있다. 

 

단순히 constructor라는 예약어로 선언하면 되며, 

클래스 메소드로 사용할 때에는 객체에 대한

메모리 할당 작업을 하게 되지만, 

 

이미 인스턴스화된 객체에서 사용될 때에는

메모리 할당 작업은 하지 않고, 

정의된 초기화 작업만 하게 된다. 

 

여기서 만드는 클래스에는 생성자로 Create라는 프로시저를 정의하는데, 

파라미터로 FName, FRegID 필드를 채울 수 있도록 선언한다.

 

마찬가지로 파괴자(destructor)도 정의할 수 있으며 

destructor라는 예약어로 선언하면 된다. 

 

이 프로시저는 객체가 파괴되기 전에 시스템 자원을

release하는 작업을 주로하게 되는데, 

 

여기서는 특별히 추가하지 않는다.

따로 파괴자를 추가하지 않아도 

 

모든 클래스는 TObject에서 파생되기 때문에

기본적인 Free, Destroy 프로시저는 정의되어 있다. .

 

이렇게 확장한 클래스의 선언부는 다음과 같다.

 

type

  TSex = (sMale, sFemale); //GetSex 함수에서 쓰임

  TPerson = class(TObject)

    FName: string;

    FRegID: string;

    constructor Create(Name, ID: string);

    function IsValid: Boolean;

    function GetSex: TSex;

    function GetAge: integer;

  end;

 

이제 각 함수를 구현해 보도록 하자.

먼저 생성자를 구현해 보자. 생성자에서는 Name, ID를 파라미터로 받아서 

이 값을 필드에 적용하여 초기화 한다.

 

constructor TPerson.Create(Name, ID: string);

begin

  FName := Name;

  FRegID := ID;

end;

 

다음으로 FRegID 필드에 저장된 주민등록번호가 잘못된 것이 

아닌지 검사하는 IsValid 함수를 구현하도록 하자. 

주민등록번호를 검증하는 방법은 주민등록번호의 13자리 중 마지막 자리를 

제외한 12자리에 각각 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5를 곱한 뒤 전체를 더한다. 

 

예를 들어, 701203-1079727 이라는 주민등록번호가 있다고 하면, 

 

(7*2) + (0*3) + (1*4) + (2*5) + (0*6) + (3*7) + (1*8) + 

(0*9) + (7*2) + (9*3) + (7*4) + (2*5) = 136 이다. 

 

이 값을 11로 나눈 나머지 값을 11에서 뺀다. 

위의 경우에는 나머지가 4이므로 11-4=7이 된다. 

이 값이 마지막 주민등록번호 값과 일치하면

일단 유효한 번호인 것이다. 

 

일종의 해싱 함수(hashing function)이다.

 

이를 이용해서 IsValid 함수를 구현해 보자.

 

function TPerson.IsValid: Boolean;

begin

  Result := False;

  if ((Length(FRegID) = 13) and (‘0000000000000’ < FRegID) and (‘9999999999999’ > FRegID)) then

  if (11 - ((StrToInt(FRegID[1]) * 2 + StrToInt(FRegID[2]) * 3 + StrToInt(FRegID[3]) * 4 + 

       StrToInt(FRegID[4]) * 5 + StrToInt(FRegID[5]) * 6 + StrToInt(FRegID[6]) * 7 + 

       StrToInt(FRegID[7]) * 8 + StrToInt(FRegID[8]) * 9 + StrToInt(FRegID[9]) * 2 +   

       StrToInt(FRegID[10]) * 3 + StrToInt(FRegID[11]) * 4 + StrToInt(FRegID[12]) * 5) mod 11)) 

       =

       StrToInt(FRegID[13]) then

    Result := True

  else

    Result := False;

end;

 

즉, 일단 FRegID 필드 값이 13 자리이고,

숫자로 이루어 졌는지 확인하고, 

각 자리의 값을 정수형으로 바꿔서

위에서 설명한 공식에 따라 

적절한 지 알아보고 적절하면 True,

그렇지 않으면 False를 반환한다.

 

Cf. 
1. 파스칼의 문자열은 일종의 배열로 생각할 수 있기 때문에, 
이런 형태의 코드가 가능한 것이다. 
예를 들어 Name이라는 문자열 변수의 값이 ‘Sample’이라고 할 때, 
Name[1], Name[2], Name[3], Name[4], Name[5]의 값은 
각각 ‘S’, ‘a’, ‘m’, ‘p’, ‘l’, ‘e’ 이다. 

2. Length 함수 문자열의 길이를 구하는 함수이다. 
델파이 1.0까지는 문자열의 0번째 요소, 즉 위의 예를 들면 Name[0] 값에 
문자열의 길이가 저장되어 있었으나, 
2.0부터는 Length 함수를 사용하여 길이를 구한다. 

3. StrToInt, IntToStr 함수 정수와 문자열의 형전환을 해주는 함수이다. 
예를 들어 IntToStr(123)의 결과값은 ‘123’이고, 
StrToInt(‘123’)의 결과값은 123이다.

 

마지막으로 GetSex와 GetAge를 구현해 보자.

 

function TPerson.GetSex: TSex;

begin

  if IsValid then

    if FRegID[7] = '1' then 

      Result := sMale else Result := sFeMale;

end;

 

function TPerson.GetAge: integer;

var

  Date: string;

begin

  if IsValid then

  begin

    Date := DateToStr(Now);

    Result := StrToInt(Copy(Date, 1, 2)) - StrToInt(Copy(FRegID, 1, 2));

 

    if (Copy(Date, 4, 2) + Copy(Date, 7, 2)) < Copy(FRegID, 3, 4) then

      Result := Result - 1;

  end;

end;

 

GetSex 함수는 주민등록번호의 7번째 자리가 ‘1’이면 남자, 

‘2’이면 여자이므로 쉽게 이해가 될 것이다. 

GetAge 함수는 일단 System의 날짜를 얻을 수 있는 

Now함수를 사용한 후 이를 문자열로 변환한다. 

그리고, 여기서 연도만을 뽑아 정수로 변환한 후, 

주민등록번호의 첫 두자리가 태어난 해를 가리키게 되므로 

이를 정수로 변환해서 뺀다. 

 

여기에 생일이 지나지 않았으면 1을 빼야 만으로 계산한 나이가 된다.

생일을 비교할 때, 입력 받은 주민등록번호 상의 생일은 ‘0301’ 과 같이 

연속된 4개의 문자로 구성되지만, DateToStr로 변환된 Date 변수의 값은

‘98-06-21’과 같은 형식으로 저장되기 때문에 이를 동등하게 비교하기 위해 

Copy 함수를 이용하여 주민등록번호 상의 생일처럼

연속된 4개의 문자로 만드는 루틴이 추가되었다.

 

그럼, 이 클래스를 활용하는 프로그램을 만들어 보자.

 

두번째 예제에 TPerson의 구현 부분을 추가하고, 

폼을 다음(그림 5-4)과 같이 디자인 한다. 

여기서도 첫번째 예제와 마찬가지로 에디트 박스를 2개 추가한다. 

여기에는 이름과 주민등록번호를 입력받을 것이다. 

그리고, 버튼을 2개 추가한 후 Name 프로퍼티를 btnAssign과 btnExecute로 설정하고, 

Caption을 각각 ‘대입’과 ‘실행’으로 설정한다.

 

(그림 5-4) 두번째 예제의 폼 디자인

 

그리고, 각 버튼의 이벤트 핸들러를 다음과 같이 작성한다.

 

procedure TForm1.btnAssignClick(Sender: TObject);

begin

  if Assigned(Person) then 

    Person.Destroy;

  Person := TPerson.Create(Edit1.Text, Edit2.Text);

end;

 

procedure TForm1.btnExecuteClick(Sender: TObject);

var

  Sex, Age: string;

begin

  if not Assigned(Person) then

  begin

    ShowMessage('클래스가 생성되지 않았습니다 !');

    Exit;

  end;

 

  if not Person.IsValid then

  begin

    ShowMessage('주민등록번호가 유효하지 않습니다');

    Exit;

  end

  else

  begin

    if Person.GetSex = sMale then 

      Sex := '남자' else Sex := '여자';

    ShowMessage(Person.FName + '씨, 당신은 ' + Sex + '이며, 만 ' +

                                IntToStr(Person.GetAge) + '세 입니다.');

  end;

end;

 

그렇게 어렵지 않은 코드이므로

자세한 설명은 생략하도록 하겠다.

참고로 제대로 된 주민등록번호를 입력했을 때와

그렇지 않았을 때의 메시지 박스는 다음과 같다.

 

(그림 5-5) 예제 실행 결과

이런 클래스의 사용 방법은 델파이에서 TComponent를 클래스를 상속해서 

더욱 재사용성이 뛰어난 컴포넌트로 개발할 수 있다. 

이를 위해서는 프로퍼티에 대한 이해와 델파이가 제공하고 있는 

컴포넌트 모델에 대한 이해가 필요한데, 

여기에 대해서는 제 4부에서 자세하게 다룰 것이다.

728x90
반응형

댓글