Monday, October 21, 2019

Defining and Implementing Interfaces in Delphi

Defining and Implementing Interfaces in Delphi In Delphi, interface has two distinct meanings. In OOP jargon, you can think of an interface as a class with no implementation. In Delphi unit definition interface section is used to declare any public sections of code that appear in a unit. This article will explain interfaces from an OOP perspective. If you are up to creating a rock-solid application in a way that your code is maintainable, reusable, and flexible the OOP nature of Delphi will help you drive the first 70% of your route. Defining interfaces and implementing them will help with the remaining 30%. Abstract Classes You can think of an interface as an abstract class with all the implementation stripped out and everything that is not public removed. An abstract class in Delphi is a class that cannot be instantiated- you cannot create an object from a class marked as abstract. Lets take a look at an example interface declaration: typeIConfigChanged interface[{0D57624C-CDDE-458B-A36C-436AE465B477}]procedure ApplyConfigChange;end; The IConfigChanged is an interface. An interface is defined much like a class, the keyword interface is used instead of class. The Guid value that follows the interface keyword is used by the compiler to uniquely identify the interface. To generate a new GUID value, just press CtrlShiftG in the Delphi IDE. Each interface you define needs a unique Guid value. An interface in OOP defines an abstraction- a template for an actual class that will implement the interface- that will implement the methods defined by the interface. An interface does not actually do anything, it only has a signature for interaction with other (implementing) classes or interfaces. The implementation of the methods (functions, procedures, and property Get/Set methods) is done in the class that implements the interface. In the interface definition, there are no scope sections (private, public, published, etc.) everything is public. An interface type can define functions, procedures (that will eventually become methods of the class that implements the interface) and properties. When an interface defines a property it must define the get/set methods - interfaces cannot define variables. As with classes, an interface can inherit from other interfaces. typeIConfigChangedMore interface(IConfigChanged)procedure ApplyMoreChanges;end; Programming Most Delphi developers when they think of interfaces they think of COM programming. However, interfaces are just an OOP feature of the language- they are not tied to COM specifically. Interfaces can be defined and implemented in a Delphi application without touching COM at all. Implementation To implement an interface you need to add the name of the interface to the class statement, as in: typeTMainForm class(TForm, IConfigChanged)publicprocedure ApplyConfigChange;end; In the above code a Delphi form named MainForm implements the IConfigChanged interface. Warning: when a class implements an interface it must implement all its methods and properties. If you fail/forget to implement a method (for example: ApplyConfigChange) a compile time error E2003 Undeclared identifier: ApplyConfigChange will occur.Warning: if you try to specify the interface without the GUID value you will receive: E2086 Type IConfigChanged is not yet completely defined. Example Consider an MDI application where several forms can be displayed to the user at one time. When the user changes the application configuration, most forms need to update their display- show/hide some buttons, update label captions, etc. You would need a simple way to notify all open forms that a change in the application configuration has happened. The ideal tool for the job was an interface. Every form that needs to be updated when the configuration changes will implement IConfigChanged. Since the configuration screen in displayed modally, when it closes the next code ensures all IConfigChanged implementing forms are notified and ApplyConfigChange is called: procedure DoConfigChange() ;varcnt : integer;icc : IConfigChanged;beginfor cnt : 0 to -1 Screen.FormCount dobeginif Supports(Screen.Forms[cnt], IConfigChanged, icc) thenicc.ApplyConfigChange;end;end; The Supports function (defined in Sysutils.pas) indicates whether a given object or interface supports a specified interface. The code iterates through the Screen.Forms collection (of the TScreen object)- all the forms currently displayed in the application. If a form Screen.Forms[cnt] supports the interface, Supports returns the interface for the last parameter parameter and returns true. Therefore, if the form implements the IConfigChanged, the icc variable can be used to call the methods of the interface as implemented by the form. Note, of course, that every form can have its own different implementation of the ApplyConfigChange procedure. Ancestors Any class you define in Delphi needs to have an ancestor. TObject is the ultimate ancestor of all objects and components. The above idea applies to interfaces also, the IInterface is the base class for all interfaces. IInterface defines 3 methods: QueryInterface, _AddRef and _Release. This means that our IConfigChanged also has those 3 methods, but we have not implemented those. This is because TForm inherits from TComponent that already implements the IInterface for you! When you want to implement an interface in a class that inherits from TObject, make sure your class inherits from TInterfacedObject instead. Since TInterfacedObject is a TObject implementing IInterface. For example: TMyClass class(TInterfacedObject, IConfigChanged)procedure ApplyConfigChange;end; In conclusion, IUnknown IInterface. IUnknown is for COM.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.