Sign in Join
Wiki copytemporary

Understanding Interfaces: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Understanding Interfaces

OldNewLine
1+## The reason for interfaces
2+
3+Classes that extend other classes can be called subclasses. For example, the bicycle class could be extended to have a mountain sub-class, and a child's bicycle (Monareta) sub-class. They inherit many of the common functions of the bicycle class, but unique options are added as stabilizer wheels for the child's bike. You can call bicycle methods, knowing that they generally apply to all types of bicycle.
4+
5+This is a traditional and standard use for classes, since sub-classes are only variations of a theme. But assuming you had an application where you had bike-class objects, cars, car washes and others and in this application you want each class to have the following method:
6+
7+``` pascal
8+ function isRecyclable : Boolean;
9+```
10+
11+This would let you know if the object contains recyclable materials. You could define a high level class that contained this method, and define all the classes derived from it. Or you could simply add the method to each sub-class. Or I could use interfaces. The interfaces would simply tidy up this situation. Defining an interface that groups these methods together, sets a standard for all classes that implement the interface. They make it easier for the programmer to discipline himself in developing the application; All classes have a set of methods that are identical and the compiler insists that all methods in an interface be implemented.
12+
13+Returning to the scenario of the recyclable object, each sub-class inherits common functions from its particular parent class. This describes the basic structure of the sub-class. It also inherits (by implementation) common functions that span all classes.
14+
15+## Example of an interface
16+
17+Like many ideas, an example is the best way to illustrate the concepts. We will do it in stages to keep things as simple as possible. First, let's define a car class:
18+
19+``` pascal
20+ type
21+ // We define our class Car
22+ TCar = class
23+
24+ private
25+ carMake : String;
26+ carAge : Byte;
27+
28+ public
29+ // Car constructor
30+ constructor Create(Make : String);
31+
32+ published
33+ // Car Properties
34+ property Make : String read carMake;
35+ property Age : Byte read carAge write carAge;
36+ end;
37+```
38+
39+This class is defined by default based on TObject since we do not specify a base class type. This class has two properties, and a constructor, which are shown here:
40+
41+``` pascal
42+ // Implementation of constructor for the Car class
43+ TCar.Create(Make : String);
44+ begin
45+ // Save the car make and default age
46+ carMake := Make;
47+ carAge := 0;
48+ end;
49+```
50+
51+Here we assign the two properties of the car: its make and age. The make is passed as a parameter and we assign a default age of 0. Now we will define another class - a bicycle class:
52+
53+``` pascal
54+ type
55+ // We define our class Bicycle
56+ TBbicycle = class
57+
58+ private
59+ cycleMale : Boolean;
60+ cycleAge : Byte ;
61+
62+ published
63+ // Bicycle Properties
64+ property isMale: Boolean read cycleIsMale;
65+ property Age : Byte read cycleAge write cycleAge;
66+
67+ // Bicycle constructor
68+ constructor Create(isMale : Boolean; Age : Byte);
69+ end;
70+```
71+
72+This class has two properties and a constructor as shown here:
73+
74+``` pascal
75+ // Constructor implementation for the bicycle class
76+ constructor TBicycle.Create(isMale : Boolean; Age : Byte);
77+ begin
78+ // Save the passed parameters
79+ CycleIsMale := isMale;
80+ CycleAge := Age;
81+ end;
82+```
83+
84+This class is a bit different from the car class, enough to see that we might not have based the car on the bicycle or the bicycle on the car. Now we will define an interface that says if a class object is recyclable:
85+
86+``` pascal
87+ type
88+ // An interface definition
89+ IRecyclable = Interface (IInterface)
90+
91+ // A single function that supports the property
92+ function materialIsRecyclable : Boolean;
93+
94+ // A single property
95+ property isRecyclable : Boolean read materialIsRecyclable ;
96+ end;
97+```
98+
99+Our interface uses the standard Iinterface definition as the basis. Interface definitions are like class definitions with all abstract elements, so we don't have to declare them as abstract - by default they are.
100+
101+This interface adds a Recyclable property to each class that implements it. Each class that implements it will have to be guaranteed to have exactly the same way of asking if it is recyclable. This is the power and benefit of interfaces - uniformity through potentially very different classes.
102+
103+Any class can implement as many interfaces as it wants - it can conform to any global standard in effect. Note that we must define the property using a function - we cannot declare a Boolean data field in the interface as long as the interfaces do not contain data.
104+
105+Now let's change our classes to support this interface definition:
106+
107+``` pascal
108+ type
109+ // We define our class Car
110+ TCar = class(TInterfacedObject, IRecyclable)
111+
112+ private
113+ carMake : String;
114+ carAge : Byte;
115+ carIsRecyclable : Boolean; // Added to support IRecyclable
116+ function materialIsRecyclable : Boolean; // Added for IRecyclable
117+
118+ public
119+ // Car constructor
120+ constructor Create(Make : String);
121+
122+ published
123+ // Car Properties
124+ property Make : String read carMake;
125+ property Age : Byte read carAge write carAge;
126+ // Added for IRecyclable
127+ property isRecyclable : Boolean read materialIsRecyclable;
128+ end;
129+```
130+
131+Note that we put the function used by the interface property isRecyclable in the private section - we want the property to be used only by the caller.
132+
133+\[Author's note: when compiled, the compiler insists on the presence of the materialIsRecyclable function, but not on the most important part - the property. As the author can see, this does not force the predominant interface option - the property!\]
134+
135+We have now based our class on the TInterfaceObject class, which provides some standard support for the classes that implement interfaces. And we have also based our class on IRecyclable, our new interface.
136+
137+But we must also declare the new materialIsRecyclable function:
138+
139+``` pascal
140+ // Car function required by the isRecyclable attribute
141+ function TCar.materialIsRecyclable : Boolean;
142+ begin
143+ Result : = carIsRecyclable;
144+ end;
145+```
146+
147+And we must not forget to assign this recyclable value. We will do it crudely here in the constructor:
148+
149+``` pascal
150+ // Constructor implmentation for the car class
151+ constructor TCar.Create(Make : String);
152+ begin
153+ // Save the car brand and assign a default age
154+ carName : = Make;
155+ carAge : = 0 ;
156+ carIsRecyclable : = true; // Assign that it is recyclable
157+ end;
158+```
159+
160+Wow! But we must do the same for the Bicycle class to show the real effect. We will see the complete code to define and use these classes, which you can copy and paste into the Code Editor:
161+
162+``` pascal
163+ unit Unit1 ;
164+
165+ {$ mode objfpc} {$ H +}
166+
167+ interface
168+
169+ use
170+ Classes , SysUtils , FileUtil , Forms , Controls , Graphics , Dialogs ;
171+
172+ type
173+ // An interface definition
174+ IRecyclable = Interface(IInterface)
175+ // A single function that supports the property
176+ function materialIsRecyclable : Boolean;
177+ // A single property
178+ property isRecyclable : Boolean read materialIsRecyclable;
179+ end;
180+
181+ // We define our Car class
182+ TCar = class(TInterfacedObject, IRecyclable)
183+
184+ private
185+ carMake : String ;
186+ carAge : Byte ;
187+ carIsRecyclable : Boolean ;
188+ function materialIsRecyclable : Boolean ; // Added for IRecyclable
189+
190+ public
191+ // Car constructor
192+ constructor Create(Make : String);
193+
194+ published
195+ // Car Properties
196+ property Make : String read carMake;
197+ property Age : Byte read carAge write carAge;
198+ // Added for IRecyclable
199+ property isRecyclable : Boolean read materialIsRecyclable ;
200+ end;
201+
202+ // We define our Bicycle class
203+ TBicycle = class(TInterfacedObject, IRecyclable)
204+
205+ private
206+ cycleIsMale : Boolean;
207+ cycleAge : Byte;
208+ function materialIsRecyclable : Boolean; // Added for IRecyclable
209+ public
210+ // Bicycle constructor
211+ constructor Create(isMale : Boolean; numWheels : Byte);
212+
213+ published
214+ // Bicycle Properties
215+ property isMale : Boolean read cycleIsMale;
216+ property Age : Byte read cycleAge write cycleAge;
217+ // Added for IRecyclable
218+ property isRecyclable : Boolean read materialIsRecyclable;
219+ end;
220+
221+ {TForm1}
222+
223+ TForm1 = class (TForm)
224+ procedure FormCreate(Sender : TObject);
225+ private
226+ {private declarations}
227+ public
228+ {public declarations}
229+ end;
230+
231+ var
232+ Form1 : TForm1;
233+
234+ implementation
235+
236+ {$R *.lfm}
237+
238+ {TForm1}
239+
240+ procedure TForm1.FormCreate(Sender : TObject);
241+ var
242+ cycleMother : TBicycle;
243+ carFather : TCar;
244+ begin
245+ // Instance our bicycle and car objects
246+ cycleMother := TBicycle.Create(false, 36);
247+ carFather := TCar.Create('Toyota Hilux');
248+
249+ // Ask if each one is recyclable
250+ if carFather.isRecyclable then
251+ ShowMessage ('Father's car is recyclable')
252+ else ShowMessage ('Father's car is not recyclable');
253+
254+ if cycleMother.isRecyclable then
255+ ShowMessage ('Mother's bicycle is recyclable')
256+ else ShowMessage ('Mother's bicycle is not recyclable');
257+ end;
258+
259+ // Implementation constructor for the Car class
260+ constructor TCar.Create(Make : String);
261+ begin
262+ // Save the car make and assign the default age
263+ carMake := Make;
264+ carAge := 0 ;
265+ carIsRecyclable := true // Assign that it is recyclable
266+ end;
267+
268+ // Car function required for the isRecyclable attribute
269+ function TCar.materialIsRecyclable : Boolean;
270+ begin
271+ Result := carIsRecyclable;
272+ end;
273+
274+ // Implementation constructor for the bicycle class
275+ constructor TBicycle.Create(isMale : Boolean; numWheels : Byte);
276+ begin
277+ // Save the parameters that were passed
278+ cycleIsMale : = isMale;
279+ cycleAge : = Age;
280+ end;
281+
282+ // Bicycle function required for isRecyclable
283+ Function TBicycle.materialIsRecyclable : Boolean;
284+ begin
285+ // We will assume that only Male bicycles are recyclable
286+ Result := self.isMale;
287+ end;
288+ end.
289+```
290+
291+When executing ... the ShowMessage function shows the following:
292+
293+`   Father's car is recyclable Mother's bicycle is not recyclable`
294+
295+This (originally Spanish) post was taken from an Internet article that I found very interesting to modify and understand the interfaces. It has always been a taboo topic to ask and when they are used, it can give your code more clarity.
296+
297+## See also
298+
299+- [[Interfaces]]
300+- [[How To Use Interfaces]]
301+- [[Accessing the Interfaces directly]]
302+
303+---
304+*From the Free Pascal wiki, page "Understanding Interfaces", as it stood on 2021-11-26 after a change by Nummer8, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history