2012년 10월 28일 일요일

인터페이스(Interface) 이해(1)


델파이는 XE2 까지 오면서 몇번의 큰 변화가 있었다고 합니다. 그중 하나가 Interface 라고 하네요. 그런데 에전의 제 수준에서 인터페이스를 이해하기가 참 어렵더라고요.
그도 그럴것이 인터페이스를 처음 접하게 된게 COM이었기에, COM도 어려운데..
2번에 걸쳐 델파이의 인터페이스를 이해해 보도록 하겠습니다.
인터페이스를 사용하는 목적은 메모리 절약(?), 다중상속, COM 지원이 가능해 집니다.
우선 클래스만으로 구현 해보도록하겠습니다.

1. 먼저 콘솔 프로젝트를 생성합니다.
2. 유니트를 하나 추가 하고 클래스를 선언합니다.
unit Unit2;
interface
type
  TMyClass=class
    fQuestion: string;
  public
    function GetQuestion: string;
    procedure SetQuestion(const Value: string);
    function Answer: string;
    property Question: string read GetQuestion write SetQuestion;
  end;
implementation
{ TMyClass }
function TMyClass.Answer: string;
begin
  Result:= 'Your Question is ' + FQuestion + '.';
end;
function TMyClass.GetQuestion: string;
begin
  Result:= fQuestion;
end;
procedure TMyClass.SetQuestion(const Value: string);
begin
  FQuestion:= Value;
end;
end.

3. 유니트 하나를 다시 추가하고 객체 생성과 소멸을 하게 합니다.
unit Unit1;
interface
uses Unit2;
function CreateObj: TMyClass;
procedure FreeObj(Obj: TMyClass);
implementation
function CreateObj: TMyClass;
begin
  Result:= TMyClass.Create;
end;
procedure FreeObj(Obj: TMyClass);
begin
  Obj.Free;
end;
end.

4. 프로젝트에서 결과를 구현합니다.
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  Unit2 in 'Unit2.pas',
  Unit1 in 'Unit1.pas',
var
  MyObj: TMyClass;
begin
  MyObj:= CreateObj;
  MyObj.Question:= 'hello';
  Writeln(MyObj.Answer);
  Readln;
  FreeObj(MyObj)
end.

이상이 우리가 통상 해오던 OOP 코딩입니다.
살펴보면 Project2 의 구현 부분이 Unit2 의 구현 부분에 종속이 되어있습니다.
즉, Unit2 의 개발이 끝나야 Project2를 구현 할 수 있다는 것입니다.

5. 클래스 구현 방식을 약간 바꾸기 위하여 새로운 Unit를 추가합니다.
unit Unit3;
interface
type
  TMyBaseClass=class
  public
    function GetQuestion: string; virtual; abstract;
    procedure SetQuestion(const Value: string); virtual; abstract;
    function Answer: string; virtual; Abstract;
    property Question: string read GetQuestion write SetQuestion;
  end;
implementation
end.
구현 부분이 없고 virtual; abstract; 지시 되어 있습니다.
이렇게 하고

6. Project2 를 아래와 같이 바꾸어 주면
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  // Unit2 in 'Unit2.pas', 구현 부분이 빠집니다.
  Unit1 in 'Unit1.pas',
  Unit3 in 'Unit3.pas';
var
  MyObj: TMyBaseClass;
begin
  MyObj:= CreateObj;
  MyObj.Question:= 'hello';
  Writeln(MyObj.Answer);
  Readln;
  // FreeObj();
  MyObj.Free;
end.
Project2 부분은 Unit2 구현 부분과 독립적으로 코딩이 가능하게 됩니다.

6.  Unit2에는  Uses 에 Unit3을 추가하고
unit Unit2;
interface
uses Unit3;
type
  TMyClass=class(TMyBaseClass)  // 수정됨
    fQuestion: string;
  public
    function GetQuestion: string; override;  // 수정됨
    procedure SetQuestion(const Value: string); override; //수정됨
    function Answer: string; override; // 수정됨
    property Question: string read GetQuestion write SetQuestion;
  end;
implementation
{ TMyClass }
function TMyClass.Answer: string;
begin
  Result:= 'Your Question is ' + FQuestion + '.';
end;
function TMyClass.GetQuestion: string;
begin
  Result:= fQuestion;
end;
procedure TMyClass.SetQuestion(const Value: string);
begin
  FQuestion:= Value;
end;
end.

7. 그러나 Unit1 은 Unit2 에 종속이 되어 있습니다.

댓글 1개:

길손 :
작성자가 댓글을 삭제했습니다.

델파이 12.1이냐 11.3이냐?

 델파이가 12.1이 나왔습니다. 혹시 11.3버전의 커뮤니티버전이 필요하시는분이 있을 수 있을 것 같아 https://altd.embarcadero.com/.../RADStudio_11_3_esd_28... 와 이것 찾느랴 엄청고생함.