DesignPatternDelphi: Difference between revisions

From 흡혈양파의 번역工房
Jump to navigation Jump to search
(DesignPatternDelphi 초기페이지 추가-스타일만 잡아놓은상태입니다.)
 
(상단 번역관련정보 추가)
Line 1: Line 1:
;Introduction to Design Patterns in Delphi
원문 사이트<br>
http://www.obsof.com/delphi_tips/pattern.html
번역진행<br>
'''박진아'''
검수진행<br>
'''없음'''
----
==Introduction to Design Patterns in Delphi==
==Introduction to Design Patterns in Delphi==



Revision as of 07:27, 29 December 2012

Introduction to Design Patterns in Delphi

원문 사이트
http://www.obsof.com/delphi_tips/pattern.html

번역진행
박진아

검수진행
없음


Introduction to Design Patterns in Delphi

This discussion paper was presented by James Heyworth to the Canberra PC Users Group Delphi SIG on 11/11/1996. 이 논의문서는 James Heyworth에 의해 Canberra PC Users Group Delphi SIG에서 1996년 11월 11일 프리젠테이션에 사용되었습니다.

Please send comments and suggestions to james@obsof.com. 문의사항이 있으시다면 james@obsof.com 으로 내용을 보내주시기 바랍니다.

서문

Design patterns are frequently recurring structures and relationships in object-oriented design. 디자인패턴은 객체지향 디자인중 관계성과 구조에 대한 주된반복을 의미합니다.

Getting to know them can help you design better, more reusable code and also help you learn to design more complex systems. 이것을 사용하면 더 나은 디자인과 더 많은 재사용가능코드, 그리고 더 복잡한 시스템을 디자인하는것을 배우는데 도움이 됩니다.

Much of the ground-breaking work on design patterns was presented in the book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson and Vlissides. 작업에 많은 개선을 주는 디자인패턴을 제공하는 책은 이것입니다. 디자인패턴 : 재사용 가능한 객체지향 소프트웨어의 요소, Gamma, Helm, Johnson and Vlissides.[1]

You might also have heard of the authors referred to as "the Gang of Four". 이 저자들은 또한 "the Gang of Four"라고 불리기도 하죠.

If you haven't read this book before and you're designing objects, it's an excellent primer to help structure your design. 당신의 객체를 디자인하기전 아직 이책을 읽지 않았다면 이건 당신의 디자인 구조에 훌륭한 입문서가 될것입니다.

To get the most out of these examples, I recommend reading the book as well. 이 예제들을 최대한 활용하기 위해서는 이 책을 읽을것을 권장합니다.

This paper takes some sample patterns from Design Patterns and discusses their implementation in Delphi. 본 문서는 디자인패턴에서 가져온 몇개 예제패턴을 델파이로 구현하였습니다.

Another good source of pattern concepts is the book Object Models: Strategies, Patterns and Applications by Peter Coad. 패턴컨셉의 또 다른 좋은 참고는 이 책입니다. Object Models :Strategies, Patterns and Applications/Peter Coad 지음.[2]

Coad's examples are more business oriented and he emphasises learning strategies to identify patterns in your own work. Coad의 예제들은 더 많은 비즈니스를 지향하며 당신의 일에서 패턴을 식별하고 학습할 수 있는 부분을 강조합니다.

델파이는 어떻게 당신이 패턴을 정의할 수 있도록 도울 수 있습니까?

Delphi implements a fully object-oriented language with many practical refinements that simplify development. 델파이 구현은 심플한 개발환경으로서 실전적이고 많은 개선이 이루어진 완벽한 객체지향 언어입니다.

A summary of Delphi class concepts can be found in the following appendix. 델파이 클래스의 개념에 대한 요약은 부록에서 찾을 수 있습니다.

The most important class attributes from a pattern perspective are the basic inheritance of classes; virtual and abstract methods; and use of protected and public scope. 패턴의 관점에서 가장 중요한 클래스의 속성은 클래스 상속의 기본- 가상 그리고 추상메소드, 그리고 protected 또는 public의 범위를 사용한다는 사실-이다.

These give you the tools to create patterns that can be reused and extended, and let you isolate varying functionality from base attributes that are unchanging. 이것(델파이)은 패턴을 재사용하고 확장할 수 있는 패턴을 생성하는데 유용하거나, 변하지않는 기본 속성을 기능에따라 다양하게 분리하는 등에 대한 유용한 도구를 제공한다.

Delphi is a great example of an extensible application, through its component architecture, IDE interfaces and tool interfaces. 델파이는 확장가능한 어플리케이션, 컴포넌트 아키텍처를 아우르는 IDE인터페이스와 도구인터페이스의 아주 좋은 예입니다.

These interfaces define many virtual and abstract constructors and operations. 이런 인터페이스는 많은수의 가상, 추상 생성자와 행동등을 정의합니다.


델파이로 만든 디자인패턴 예제

I should note from the outset, there may be alternative or better ways to implement these patterns and I welcome your suggestions on ways to improve the design. 일단 먼저 말할것이 있는데, 이것에 대한 대안이라거나 또는 패턴을 구현하기위한 보다 좋은 방법이 있다면 내게 방법을 알려주세요. 환영합니다.

The following patterns from the book Design Patterns are discussed and illustrated in Delphi to give you a starting point for implementing your own Delphi patterns. 디자인패턴 책에 있는 패턴을 따라가다보면, 델파이패턴을 구현하는데 있어 델파이에서 논의 및 설계를 만들 수 있는 시작점을 당신은 가지게 됩니다.

Pattern Name Definition 패턴 이름 정의

  • Singleton "Ensure a class has only one instance, and provide a global point of access to it."
  • Adapter "Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces."
  • Template Method "Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure."
  • Builder "Separate the construction of a complex object from its representation so that the same construction process can create different representations."
  • Abstract Factory "Provide an interface for creating families of related or dependant objects without specifying their concrete classes."
  • Factory Method "Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses."

주의: 이 정의들은 디자인패턴에서 가져왔습니다.

Pattern: Singleton

정의

"Ensure a class has only one instance, and provide a global point of access to it." This is one of the easiest patterns to implement.

델파이에서의 응용

There are several examples of this sort of class in the Delphi VCL, such as TApplication, TScreen or TClipboard. The pattern is useful whenever you want a single global object in your application. Other uses might include a global exception handler, application security, or a single point of interface to another application.

구현 예제

To implement a class of this type, override the constructor and destructor of the class to refer to a global (interface) variable of the class. Abort the constructor if the variable is assigned, otherwise create the instance and assign the variable.

In the destructor, clear the variable if it refers to the instance being destroyed. Note: To make the creation and destruction of the single instance automatic, include its creation in the initialization section of the unit. To destroy the instance, include its destruction in an ExitProc (Delphi 1) or in the finalization section of the unit (Delphi 2). The following Delphi 1 example illustrates two singleton classes, one derived from TComponent and another derived from TObject.


unit Singletn;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs;

type
  TCSingleton = class(TComponent)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  TOSingleton = class(TObject)
  public
    constructor Create;
    destructor Destroy; override;
  end;

var
  Global_CSingleton: TCSingleton;
  Global_OSingleton: TOSingleton;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Design Patterns', [TCSingleton]);
end;

{ TCSingleton }

constructor TCSingleton.Create(AOwner: TComponent);
begin
  if Global_CSingleton <> nil then
    {NB could show a message or raise a different exception here}
    Abort
  else begin
    inherited Create(AOwner);
    Global_CSingleton := Self;
  end;
end;

destructor TCSingleton.Destroy;
begin
  if Global_CSingleton = Self then
    Global_CSingleton := nil;
  inherited Destroy;
end;

{ TOSingleton }

constructor TOSingleton.Create;
begin
  if Global_OSingleton <> nil then
    {NB could show a message or raise a different exception here}
    Abort
  else
    Global_OSingleton := Self;
end;

destructor TOSingleton.Destroy;
begin
  if Global_OSingleton = Self then
    Global_OSingleton := nil;
  inherited Destroy;
end;

procedure FreeGlobalObjects; far;
begin
  if Global_CSingleton <> nil then
    Global_CSingleton.Free;
  if Global_OSingleton <> nil then
    Global_OSingleton.Free;
end;

begin
  AddExitProc(FreeGlobalObjects);
end.


Pattern: Adapter

Definition

"Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces."

Applications in Delphi

A typical example of this is the wrapper Delphi generates when you import a VBX or OCX. Delphi generates a new class which translates the interface of the external control into a Pascal compatible interface. Another typical case is when you want to build a single interface to old and new systems. Note Delphi does not allow class adaption through multiple inheritance in the way described in Design Patterns. Instead, the adapter needs to refer to a specific instance of the old class.

Implementation Example

The following example is a simple (read only) case of a new customer class, an adapter class and an old customer class. The adapter illustrates handling the year 2000 problem, translating an old customer record containing two digit years into a new date format. The client using this wrapper only knows about the new customer class. Translation between classes is handled by the use of virtual access methods for the properties. The old customer class and adapter class are hidden in the implementation of the unit.


unit Adapter;

interface

uses SysUtils, Classes;

type

  { The new class }
  TNewCustomer = class
  private
    FCustomerID: Longint;
    FFirstName: string;
    FLastName: string;
    FDOB: TDateTime;
  protected
    function GetCustomerID: Longint; virtual;
    function GetFirstName: string; virtual;
    function GetLastName: string; virtual;
    function GetDOB: TDateTime; virtual;
  public
    constructor Create(CustID: Longint); virtual;
    property CustomerID: Longint read GetCustomerID;
    property FirstName: string read GetFirstName;
    property LastName: string read GetLastName;
    property DOB: TDateTime read GetDOB;
  end;

  { An interface method }
  { Lets us hide details of TOldCustomer from the client }

function GetCustomer(CustomerID: Longint): TNewCustomer;

implementation

const
  Last_OldCustomer_At_Year_2000 = 15722;
  Last_OldCustomer_In_Database = 30000;

{ The new class }

constructor TNewCustomer.Create(CustID: Longint);
begin
  FCustomerID := CustID;
  FFirstName := 'A';
  FLastName := 'New_Customer';
  FDOB := Now;
end;

function TNewCustomer.GetCustomerID: Longint;
begin
  Result := FCustomerID;
end;

function TNewCustomer.GetFirstName: string;
begin
  Result := FFirstName;
end;

function TNewCustomer.GetLastName: string;
begin
  Result := FLastName;
end;

function TNewCustomer.GetDOB: TDateTime;
begin
  Result := FDOB;
end;

type
  { The old class }
  TOldDOB = record
    Day: 0..31;
    Month: 1..12;
    Year: 0..99;
  end;

  TOldCustomer = class
    FCustomerID: Integer;
    FName: string;
    FDOB: TOldDOB;
  public
    constructor Create(CustID: Integer);
    property CustomerID: Integer read FCustomerID;
    property Name: string read FName;
    property DOB: TOldDOB read FDOB;
  end;

constructor TOldCustomer.Create(CustID: Integer);
begin
  FCustomerID := CustomerID;
  FName := 'An Old_Customer';
  with FDOB do begin
    Day := 1;
    Month := 1;
    Year := 1;
  end;
end;

type
  { The Adapter class }
  TAdaptedCustomer = class(TNewCustomer)
  private
    FOldCustomer: TOldCustomer;
  protected
    function GetCustomerID: Longint; override;
    function GetFirstName: string; override;
    function GetLastName: string; override;
    function GetDOB: TDateTime; override;
  public
    constructor Create(CustID: Longint); override;
    destructor Destroy; override;
  end;

{ The Adapter class }

constructor TAdaptedCustomer.Create(CustID: Longint);
begin
  inherited Create(CustID);
  FOldCustomer := TOldCustomer.Create(CustID);
end;

destructor TAdaptedCustomer.Destroy;
begin
  FOldCustomer.Free;
  inherited Destroy;
end;

function TAdaptedCustomer.GetCustomerID: Longint;
begin
  Result := FOldCustomer.CustomerID;
end;

function TAdaptedCustomer.GetFirstName: string;
var
  SpacePos: integer;
begin
  SpacePos := Pos(' ', FOldCustomer.Name);
  if SpacePos = 0 then
    Result := ''
  else
    Result := Copy(FOldCustomer.Name,1,SpacePos-1);
end;

function TAdaptedCustomer.GetLastName: string;
var
  SpacePos: integer;
begin
  SpacePos := Pos(' ', FOldCustomer.Name);
  if SpacePos = 0 then
    Result := FOldCustomer.Name
  else
    Result := Copy(FOldCustomer.Name,SpacePos+1,255);
end;

function TAdaptedCustomer.GetDOB: TDateTime;
var
  FullYear: Word;
begin
  if CustomerID > Last_OldCustomer_At_Year_2000 then
    FullYear := 2000 + FOldCustomer.DOB.Year
  else
    FullYear := 1900 + FOldCustomer.DOB.Year;
  Result := EncodeDate(FullYear, FOldCustomer.DOB.Month, FOldCustomer.DOB.Day);
end;

function GetCustomer(CustomerID: Longint): TNewCustomer;
begin
  if CustomerID > Last_OldCustomer_In_Database then
    Result := TNewCustomer.Create(CustomerID)
  else
    Result := TAdaptedCustomer.Create(CustomerID) as TNewCustomer;
end;

end.


Pattern: Template Method

Definition

"Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure." This pattern is essentially an extension of abstract methods to more complex algorithms.

Applications in Delphi

Abstraction is implemented in Delphi by abstract virtual methods. Abstract methods differ from virtual methods by the base class not providing any implementation. The descendant class is completely responsible for implementing an abstract method. Calling an abstract method that has not been overridden will result in a runtime error. A typical example of abstraction is the TGraphic class.

TGraphic is an abstract class used to implement TBitmap, TIcon and TMetafile. Other developers have frequently used TGraphic as the basis for other graphics objects such as PCX, GIF, JPG representations. TGraphic defines abstract methods such as Draw, LoadFromFile and SaveToFile which are then overridden in the concrete classes. Other objects that use TGraphic, such as a TCanvas only know about the abstract Draw method, yet are used with the concrete class at runtime. Many classes that use complex algorithms are likely to benefit from abstraction using the template method approach. Typical examples include data compression, encryption and advanced graphics processing.

Implementation Example

To implement template methods you need an abstract class and concrete classes for each alternate implementation. Define a public interface to an algorithm in an abstract base class. In that public method, implement the steps of the algorithm in calls to protected abstract methods of the class. In concrete classes derived from the base class, override each step of the algorithm with a concrete implementation specific to that class. This example shows some very simple alogrithm steps, but illustrates the principle of deferring implementation to a subclass.


unit Tpl_meth;

interface

type
  TAbstractTemplateClass = class(TObject)
  protected
    function Algorithm_StepA: Integer; virtual; abstract;
    function Algorithm_StepB: Integer; virtual; abstract;
    function Algorithm_StepC: Integer; virtual; abstract;
  public
    function Algorithm: Integer;
  end;

  TConcreteClassA = class(TAbstractTemplateClass)
  protected
    function Algorithm_StepA: Integer; override;
    function Algorithm_StepB: Integer; override;
    function Algorithm_StepC: Integer; override;
  end;

  TConcreteClassB = class(TAbstractTemplateClass)
  protected
    function Algorithm_StepA: Integer; override;
    function Algorithm_StepB: Integer; override;
    function Algorithm_StepC: Integer; override;
  end;


Pattern: Builder

Definition

"Separate the construction of a complex object from its representation so that the same construction process can create different representations." A Builder seems similar in concept to the Abstract Factory. The difference as I see it is the Builder refers to single complex objects of different concrete classes but containing multiple parts, whereas the abstract factory lets you create whole families of concrete classes. For example, a builder might construct a house, cottage or office. You might employ a different builder for a brick house or a timber house, though you would give them both similar instructions about the size and shape of the house. On the other hand the factory generates parts and not the whole. It might produce a range of windows for buildings, or it might produce a quite different range of windows for cars.

Applications in Delphi

The functionality used in Delphi's VCL to create forms and components is similar in concept to the builder. Delphi creates forms using a common interface, through Application.CreateForm and through the TForm class constructor. TForm implements a common constructor using the resource information (DFM file) to instantiate the components owned by the form. Many descendant classes reuse this same construction process to create different representations. Delphi also makes developer extensions easy. TForm's OnCreate event also adds a hook into the builder process to make the functionality easy to extend.

Implementation Example

The following example includes a class TAbstractFormBuilder and two concrete classes TRedFormBuilder and TBlueFormBuilder. For ease of development some common functionality of the concrete classes has been moved into the shared TAbstractFormBuilder class.


type
  TAbstractFormBuilder = class
  private
    FForm: TForm;
    procedure BuilderFormClose(Sender: TObject; var Action: TCloseAction);
  protected
    function GetForm: TForm; virtual;
  public
    procedure CreateForm(AOwner: TComponent); virtual;
    procedure CreateSpeedButton; virtual; abstract;
    procedure CreateEdit; virtual; abstract;
    procedure CreateLabel; virtual; abstract;
    property Form: TForm read GetForm;
  end;

type
  TRedFormBuilder = class(TAbstractFormBuilder)
  private
    FNextLeft, FNextTop: Integer;
  public
    procedure CreateForm(AOwner: TComponent); override;
    procedure CreateSpeedButton; override;
    procedure CreateEdit; override;
    procedure CreateLabel; override;
  end;

type
  TBlueFormBuilder = class(TAbstractFormBuilder)
  private
    FNextLeft, FNextTop: Integer;
  public
    procedure CreateForm(AOwner: TComponent); override;
    procedure CreateSpeedButton; override;
    procedure CreateEdit; override;
    procedure CreateLabel; override;
  end;


At runtime the client application instructs one of the concrete classes to create parts using the public part creation procedures. The concrete builder instance is passed to the folliwing procedure:

procedure TForm1.Create3ComponentFormUsingBuilder(ABuilder: TAbstractFormBuilder);
var
  NewForm: TForm;
begin
  with ABuilder do begin
    CreateForm(Application);
    CreateEdit;
    CreateSpeedButton;
    CreateLabel;
    NewForm := Form;
    if NewForm <> nil then NewForm.Show;
  end;
end;


Pattern: Abstract Factory

Definition

"Provide an interface for creating families of related or dependant objects without specifying their concrete classes." The Factory Method pattern below is commonly used in this pattern.

Applications in Delphi

This pattern is ideal where you want to isolate your application from the implementation of the concrete classes. For example if you wanted to overlay Delphi's VCL with a common VCL layer for both 16 and 32 bit applications, you might start with the abstract factory as a base.

Implementation Example

The following example uses an abstract factory and two concrete factory classes to implement different styles of user interface components. TOAbstractFactory is a singleton class, since we usually want one factory to be used for the whole application.


TOAbstractFactory = class(TObject)
  public
    constructor Create;
    destructor Destroy; override;
    { abstract widget constructors }
    function CreateSpeedButton(AOwner: TComponent): TSpeedButton; virtual; abstract;
    function CreateEdit(AOwner: TComponent): TEdit; virtual; abstract;
    function CreateLabel(AOwner: TComponent): TLabel; virtual; abstract;
  end;

TORedFactory and TOBlueFactory override the abstract interface to support different widget styles.

TORedFactory = class(TOAbstractFactory)
  public
    { concrete widget constructors }
    function CreateSpeedButton(AOwner: TComponent): TSpeedButton; override;
    function CreateEdit(AOwner: TComponent): TEdit; override;
    function CreateLabel(AOwner: TComponent): TLabel; override;
  end;

TOBlueFactory = class(TOAbstractFactory)
  public
    { concrete widget constructors }
    function CreateSpeedButton(AOwner: TComponent): TSpeedButton; override;
    function CreateEdit(AOwner: TComponent): TEdit; override;
    function CreateLabel(AOwner: TComponent): TLabel; override;
  end;

At runtime, our client application instantiates the abstract factory with a concrete class and then uses the abstract interface. Parts of the client application that use the factory don't need to know which concrete class is actually in use.

Pattern: Factory Method

Definition

"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses." The Abstact Factory pattern can be viewed as a collection of Factory Methods.

Applications in Delphi

This pattern is useful when you want to encapsulate the construction of a class and isolate knowledge of the concrete class from the client application through an abstract interface. One example of this might arise if you had an object oriented business application potentially interfacing to multiple target DBMS. The client application only wants to know about the business classes, not about their implementation-specific storage and retrieval.

Implementation Example In the Abstract Factory example, each of the virtual widget constructor functions is a Factory Method. In their implementation we define a specific widget class to return.


TRedSpeedButton = class(TSpeedButton)
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TRedSpeedButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Font.Color := clRed;
end;

function TORedFactory.CreateSpeedButton(AOwner: TComponent): TSpeedButton;
begin
  Result := TRedSpeedButton.Create(AOwner);
end;


Appendix: Key Elements of Delphi Class Definitions

Unit Structure

Delphi units (.PAS files) allow declaration of interface and implementation sections. The interface defines the part that is visible to other units using that unit. The keyword uses can be added to a unit's interface or implementation section to list the other units that your unit uses. This indicates to the compiler that your unit refers to parts of the used unit's interface. Parts of a unit declared in the implementation section are all private to that unit, i.e. never visible to any other unit. Types, functions and procedures declared in the interface of a unit must have a corresponding implementation, or be declared as external (e.g. a call to a function in a DLL).

Class Interfaces

Classes are defined as types in Delphi and may contain fields of standard data types or other objects, methods declared as functions or procedures, and properties. The type declaration of a class defines its interface and the scope of access to fields, methods and properties of the class. Class interfaces are usually defined in the interface of a unit to make them accessible to other modules using that unit. However they don't need to be. Sometimes a type declaration of a class may be used only within the implementation part of a unit.

Properties

Properties are a specialised interface to a field of a defined type, allowing access control through read and write methods. Properties are not virtual, you can replace a property with another property of the same name, but the parent class doesn't know about the new property. It is however possible to make the access methods of a property virtual.

Inheritance

Delphi's inheritance model is based on a single hierarchy. Every class inherits from TObject and can have only one parent. A descendant class inherits all of the interface and functionality of its parent class, subject to the scope described below. Multiple inheritance from more than one parent is not allowed directly. It can be implemented by using a container class to create instances one or more other classes and selectively expose parts of the contained classes.

Private, Protected, Public and Published Scope

Scope refers to the visibility of methods and data defined in the interface of a class, i.e. what parts of the class are accessible to the rest of the application or to descendant classes. The default scope is public, for instance the component instances you add to a form at design time. Public says "come and get me"; it makes the data or method visible to everything at runtime. Published parts of a class are a specialized form of Public scope. They indicate special behaviour for classes derived from TPersistent. A persistent class can save and restore its published properties to persistent storage using Delphi's standard streaming methods. Published properties also interact with Delphi Object Inspector in the IDE. A class must descend from TPersistent in order to use Published. There's also not much point in publishing methods, since you can't store them, although Delphi's compiler doesn't stop you. Published also lets another application access details of the class through Delphi's runtime type information. This would be rarely used, except in Delphi's design time interaction with its VCL. Encapsulation or information hiding is essential to object orientation, so Protected and Private scope let you narrow the access to parts of a class. Protected parts are visible only to descendant classes, or to other classes defined in the same unit. Private parts are visible only to the defining class, or to other classes defined in the same unit. It's important to note that once something is given public or published scope, it cannot be hidden in descendant classes.

Static, Virtual and Dynamic Methods; Override and Inherited

Methods declared as virtual or dynamic let you change their behaviour using override in a descendant class. You're unlikely to see a virtual method in the private part of a class, since it could only be overridden in the same unit, although Delphi's compiler doesn't stop you from doing this. Override indicates that your new method replaces the method of the same name from the parent class. The override must be declared with the same name and parameters as the original method. When a method is overridden, a call to the parent class's method actually executes the override method in the real class of the object. Static methods on the other hand have no virtual or override declaration. You can replace a method of a class in a descendant class by redeclaring another method, however this is not object oriented. If you reference your descendant class as the parent type and try to call the replaced method, the static method of the parent class is executed. So in most cases, it's a bad idea to replace a static method. Virtual and dynamic methods can be used interchangeably. They differ only in their treatment by the compiler and runtime library. Delphi's help explains that dynamic methods have their implementation resolved at compile time and run slightly faster, whereas virtual methods are resolved at runtime, resulting in slightly slower access but a smaller compiled program. Virtual is usually the preferred declaration. Delphi's help suggests using dynamic when you have a base class with many descendants that may not override the method. The inherited directive lets you refer back to a property or method as it was declared in the parent class. This is most often used in the implementation of an override method, to call the inherited method of the parent class and then supplement its behaviour.

Abstract Methods

Abstract is used in base classes to declare a method in the interface and defer its implementation to a descendant class. I.e. it defines an interface, but not the underlying operation. Abstract must be used with the virtual or dynamic directive. Abstract methods are never implemented in the base class and must be implemented in descendant classes to be used. A runtime error occurs if you try to execute an abstract method that is not overridden. Calling inherited within the override implementation of an abstract method will also result in a runtime error, since there is no inherited behaviour.

Messages

Delphi's handling of Windows messages is a special case of virtual methods. Message handlers are implemented in classes that descend from TControl. I.e classes that have a handle and can receive messages. Message handlers are always virtual and can be declared in the private part of a class interface, yet still allow the inherited method to be called. Inherited in a message handler just uses the keyword inherited, there is no need to supply the name of the method to call.

Events

Events are also an important characteristic of Delphi, since they let you delegate extensible behaviour to instances of a class. Events are properties that refer to a method of another object. Events are not inherited in Delphi 1; Delphi 2 extends this behaviour to let you use inherited in an event. . Inherited in an event handler just uses the keyword inherited, there is no need to supply the name of the method to call. Events are particularly important to component developers, since they provide a hook for the user of the component to modify its behaviour in a way that may not be foreseen at the time the component is written.

Constructors and Destructors

The constructor and destructor are two special types of methods. The constructor initializes a class instance (allocates memory initialized to 0) and returns a reference (pointer) to the object. The destructor deallocates memory used by the object (but not the memory of other objects created by the object). Classes descended from TObject have a static constructor, Create, and a virtual destructor Destroy. TComponent introduces a new public property, the Owner of the component and this must be initialized in the constructor. TComponent's constructor is declared virtual, i.e. it can be overridden in descendant classes. It is essential when you override a virtual constructor or destructor in a TComponent descendant to include a call to the inherited method.


Bibliography

  1. Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma et al., Addison-Wesley, Massachusetts, 1995.
  2. Object Models: Strategies, Patterns and Applications, Peter Coad et al., Prentice-Hall, New Jersey, 1995.


Copyright © 1996, Objective Software Technology Pty Limited. This paper may be freely distributed in its entirety, providing the source is acknowledged.

Portions quoted from Design Patterns are Copyright © 1995, Addison Wesley Publishing Company.

Notes

  1. 이름이 좀 이상하게 들어가 있지만 책 이름입니다. http://ko.wikipedia.org/wiki/%EB%94%94%EC%9E%90%EC%9D%B8_%ED%8C%A8%ED%84%B4_(%EC%B1%85) 옆의 위키페이지를 보시면 아시겠지만 이미 한국어로 번역이 된 책입니다.
  2. http://www.amazon.com/Object-Models-Strategies-Patterns-Applications/dp/0138401179 이라는 책입니다. 아직 번역본은 딱히 보지 못한거같네요.