Interfaces are supported using the classic Delphi syntax (except the GUID part which is not supported).
Interfaces can define properties, which are syntax sugar to their methods. They can be implemented by Classes.
Pas2JS fully supports interfaces. There is no need for TInterfacedObject, interfaces can be applied directly to TObject since JavaScript does not have a mechanism for observing reference counts.
The Interface keyword is used in two different ways:
Version 1: It starts the definition of external interface of a Unit. Declarations here are externally visible by other units. All of these declarations must be implemented in the Implementation section. The Uses statement, if present,
must be at the start.
Version 2: In Object Oriented programming, we often use Abstract class methods in a base class as a placeholder.
All derived classes must implement these methods.
Taking this one step further, an Interface defines a grouping of just abstract properties and methods.
It provides a template for a class to use to ensure consistency. It is like a class with only abstract methods.
It has the benefits that classes can be based on one parent class, and implement one or more interfaces.
It adds a predictable flavour of operation to each class that implements the interface.
Note: The class implementing an interface can be derived from any parent. There is no TInterfacedObject class.
An interface example
Like many ideas, an example is the best way to illustrate the concepts. We'll do it in stages to keep things as simple as possible.
First, let us define a interface.
Interface, it makes it easier for the programmer to be disciplined in developing the application; all of the classes have
an additional set of methods that are identical. And Pas2JS insists that all of the methods in an interface are implemented.
unit uTest;
interface
uses
SmartCL.System;
type
// An interface definition
IMyInterface = interface
procedure myInternalMethod;
end;
type
// An interface definition
IVehicle = Interface(IInterface)
// Properties and their functions
function GetAge : Integer;
function GetMiles : Integer;
property age : Integer read GetAge;
property miles : Integer read GetMiles;
// Non-property function
function GetValue : Float;
end;
implementation
end.
|
Our interface uses the standard IInterface interface definition as a base. Interfaces definitions are like class definitions with
all abstract elements. We do not have to declare them as abstract - they are by default.
This interface adds two properties. The the power and benefit of interfaces is the uniformity across potentially very different
classes.
How to implement a interface?
unit uTestImpl;
interface
uses
SmartCL.System, uTest;
type
TMyObject = class(TObject,IMyInterface)
public
{ IMyInterface Implementation }
procedure myInternalMethod;
end;
// Implement this interface in a car class
// Note that there is no TInterfacedObject class.
TCar = Class(IVehicle)
private
fAge, fMiles : Integer;
fCarType : string;
function GetAge : Integer;
function GetMiles : Integer;
public
property age : Integer read GetAge;
property miles : Integer read GetMiles;
property carType : string read fCarType;
// Non-property function
function GetValue : Float;
published
constructor Create(age, miles : Integer; carType : string);
end;
implementation
{ TMyObject }
procedure TMyObject.myInternalMethod;
begin
WriteLn('Hello warleyalex');
end;
// Car constructor
constructor TCar.Create(age, miles: Integer; carType: string);
begin
// Save parameters
fAge := age;
fMiles := miles;
fCarType := carType;
end;
// Get the age of the car
function TCar.GetAge: Integer;
begin
Result := fAge;
end;
// Get the mileage of the car
function TCar.GetMiles: Integer;
begin
Result := fMiles;
end;
// Calculate the car value
function TCar.GetValue: Float;
begin
Result := 10000.0 - ((age * miles)/10.0);
end;
end.
|
Note that:
· | We place the function used by the interface GetAge and GetMIles property in the private section. We only want the caller to use the property. |
· | We must declare the GetAge and GetMiles functions. |
· | We must not forget to set this Age, Miles and CarType values. We'll do it in the constructor:
|
How to instantiate our Car object?
unit Form1;
interface
uses
SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms,
uTestImpl,
SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Button;
type
TForm1 = class(TW3Form)
procedure W3Button1Click(Sender: TObject);
private
{$I 'Form1:intf'}
protected
procedure InitializeForm; override;
procedure InitializeObject; override;
procedure Resize; override;
end;
implementation
{ TForm1 }
procedure TForm1.W3Button1Click(Sender: TObject);
var
car : TCar;
obj : TMyObject;
begin
obj := TMyObject.Create();
obj.myInternalMethod;
car := TCar.Create(1, 2076, 'Honda Jazz');
// Show the current value of this car
WriteLn(Format('My %s car is %d years old, %d miles, value %d',
[car.carType, car.age, car.miles, car.GetValue]));
end;
procedure TForm1.InitializeForm;
begin
inherited;
// this is a good place to initialize components
end;
procedure TForm1.InitializeObject;
begin
inherited;
{$I 'Form1:impl'}
end;
procedure TForm1.Resize;
begin
inherited;
end;
initialization
Forms.RegisterForm({$I %FILE%}, TForm1);
{ TMyObject }
end.
|
Hello warleyalex
My Honda Jazz car is 1 years old, 2076 miles, value 9792.4
|