Sign in Join
Wiki copytemporary

Understanding Interfaces: what changed

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

OldNewLine
11## The reason for interfaces
22
33Classes 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.
44
55This 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:
66
77``` pascal
88 function isRecyclable : Boolean;
99```
1010
1111This 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.
1212
1313Returning 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.
1414
1515## Example of an interface
1616
1717Like 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:
1818
1919``` pascal
2020 type
2121 // We define our class Car
2222 TCar = class
2323
2424 private
2525 carMake : String;
2626 carAge : Byte;
2727
2828 public
2929 // Car constructor
3030 constructor Create(Make : String);
3131
3232 published
3333 // Car Properties
3434 property Make : String read carMake;
3535 property Age : Byte read carAge write carAge;
3636 end;
3737```
3838
3939This 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:
4040
4141``` pascal
4242 // Implementation of constructor for the Car class
4343 TCar.Create(Make : String);
4444 begin
4545 // Save the car make and default age
4646 carMake := Make;
4747 carAge := 0;
4848 end;
4949```
5050
5151Here 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:
5252
5353``` pascal
5454 type
5555 // We define our class Bicycle
5656 TBbicycle = class
5757
5858 private
5959 cycleMale : Boolean;
6060 cycleAge : Byte ;
6161
6262 published
6363 // Bicycle Properties
6464 property isMale: Boolean read cycleIsMale;
6565 property Age : Byte read cycleAge write cycleAge;
6666
6767 // Bicycle constructor
6868 constructor Create(isMale : Boolean; Age : Byte);
6969 end;
7070```
7171
7272This class has two properties and a constructor as shown here:
7373
7474``` pascal
7575 // Constructor implementation for the bicycle class
7676 constructor TBicycle.Create(isMale : Boolean; Age : Byte);
7777 begin
7878 // Save the passed parameters
7979 CycleIsMale := isMale;
8080 CycleAge := Age;
8181 end;
8282```
8383
8484This 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:
8585
8686``` pascal
8787 type
8888 // An interface definition
8989 IRecyclable = Interface (IInterface)
9090
9191 // A single function that supports the property
9292 function materialIsRecyclable : Boolean;
9393
9494 // A single property
9595 property isRecyclable : Boolean read materialIsRecyclable ;
9696 end;
9797```
9898
9999Our 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.
100100
101101This 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.
102102
103103Any 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.
104104
105105Now let's change our classes to support this interface definition:
106106
107107``` pascal
108108 type
109109 // We define our class Car
110110 TCar = class(TInterfacedObject, IRecyclable)
111111
112112 private
113113 carMake : String;
114114 carAge : Byte;
115115 carIsRecyclable : Boolean; // Added to support IRecyclable
116116 function materialIsRecyclable : Boolean; // Added for IRecyclable
117117
118118 public
119119 // Car constructor
120120 constructor Create(Make : String);
121121
122122 published
123123 // Car Properties
124124 property Make : String read carMake;
125125 property Age : Byte read carAge write carAge;
126126 // Added for IRecyclable
127127 property isRecyclable : Boolean read materialIsRecyclable;
128128 end;
129129```
130130
131131Note 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.
132132
133133\[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!\]
134134
135135We 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.
136136
137137But we must also declare the new materialIsRecyclable function:
138138
139139``` pascal
140140 // Car function required by the isRecyclable attribute
141141 function TCar.materialIsRecyclable : Boolean;
142142 begin
143143 Result : = carIsRecyclable;
144144 end;
145145```
146146
147147And we must not forget to assign this recyclable value. We will do it crudely here in the constructor:
148148
149149``` pascal
150150 // Constructor implmentation for the car class
151151 constructor TCar.Create(Make : String);
152152 begin
153153 // Save the car brand and assign a default age
154154 carName : = Make;
155155 carAge : = 0 ;
156156 carIsRecyclable : = true; // Assign that it is recyclable
157157 end;
158158```
159159
160160Wow! 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:
161161
162162``` pascal
163163 unit Unit1 ;
164164
165165 {$ mode objfpc} {$ H +}
166166
167167 interface
168168
169169 use
170170 Classes , SysUtils , FileUtil , Forms , Controls , Graphics , Dialogs ;
171171
172172 type
173173 // An interface definition
174174 IRecyclable = Interface(IInterface)
175175 // A single function that supports the property
176176 function materialIsRecyclable : Boolean;
177177 // A single property
178178 property isRecyclable : Boolean read materialIsRecyclable;
179179 end;
180180
181181 // We define our Car class
182182 TCar = class(TInterfacedObject, IRecyclable)
183183
184184 private
185185 carMake : String ;
186186 carAge : Byte ;
187187 carIsRecyclable : Boolean ;
188188 function materialIsRecyclable : Boolean ; // Added for IRecyclable
189189
190190 public
191191 // Car constructor
192192 constructor Create(Make : String);
193193
194194 published
195195 // Car Properties
196196 property Make : String read carMake;
197197 property Age : Byte read carAge write carAge;
198198 // Added for IRecyclable
199199 property isRecyclable : Boolean read materialIsRecyclable ;
200200 end;
201201
202202 // We define our Bicycle class
203203 TBicycle = class(TInterfacedObject, IRecyclable)
204204
205205 private
206206 cycleIsMale : Boolean;
207207 cycleAge : Byte;
208208 function materialIsRecyclable : Boolean; // Added for IRecyclable
209209 public
210210 // Bicycle constructor
211211 constructor Create(isMale : Boolean; numWheels : Byte);
212212
213213 published
214214 // Bicycle Properties
215215 property isMale : Boolean read cycleIsMale;
216216 property Age : Byte read cycleAge write cycleAge;
217217 // Added for IRecyclable
218218 property isRecyclable : Boolean read materialIsRecyclable;
219219 end;
220220
221221 {TForm1}
222222
223223 TForm1 = class (TForm)
224224 procedure FormCreate(Sender : TObject);
225225 private
226226 {private declarations}
227227 public
228228 {public declarations}
229229 end;
230230
231231 var
232232 Form1 : TForm1;
233233
234234 implementation
235235
236236 {$R *.lfm}
237237
238238 {TForm1}
239239
240240 procedure TForm1.FormCreate(Sender : TObject);
241241 var
242242 cycleMother : TBicycle;
243243 carFather : TCar;
244244 begin
245245 // Instance our bicycle and car objects
246246 cycleMother := TBicycle.Create(false, 36);
247247 carFather := TCar.Create('Toyota Hilux');
248248
249249 // Ask if each one is recyclable
250250 if carFather.isRecyclable then
251251 ShowMessage ('Father's car is recyclable')
252252 else ShowMessage ('Father's car is not recyclable');
253253
254254 if cycleMother.isRecyclable then
255255 ShowMessage ('Mother's bicycle is recyclable')
256256 else ShowMessage ('Mother's bicycle is not recyclable');
257257 end;
258258
259259 // Implementation constructor for the Car class
260260 constructor TCar.Create(Make : String);
261261 begin
262262 // Save the car make and assign the default age
263263 carMake := Make;
264264 carAge := 0 ;
265265 carIsRecyclable := true // Assign that it is recyclable
266266 end;
267267
268268 // Car function required for the isRecyclable attribute
269269 function TCar.materialIsRecyclable : Boolean;
270270 begin
271271 Result := carIsRecyclable;
272272 end;
273273
274274 // Implementation constructor for the bicycle class
275275 constructor TBicycle.Create(isMale : Boolean; numWheels : Byte);
276276 begin
277277 // Save the parameters that were passed
278278 cycleIsMale : = isMale;
279279 cycleAge : = Age;
280280 end;
281281
282282 // Bicycle function required for isRecyclable
283283 Function TBicycle.materialIsRecyclable : Boolean;
284284 begin
285285 // We will assume that only Male bicycles are recyclable
286286 Result := self.isMale;
287287 end;
288288 end.
289289```
290290
291291When executing ... the ShowMessage function shows the following:
292292
293-`   Father's car is recyclable Mother's bicycle is not recyclable`
293+```text
294+ Father's car is recyclable Mother's bicycle is not recyclable
295+```
294296
295297This (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.
296298
297299## See also
298300
299301- [[Interfaces]]
300302- [[How To Use Interfaces]]
301303- [[Accessing the Interfaces directly]]
302304
303305---
304306*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