Definiowanie i wdrażanie interfejsów w Delphi

W Delfy, „interfejs” ma dwa różne znaczenia. W OOP żargon, interfejs można traktować jak klasę bez implementacji. W sekcji interfejsu jednostki Delphi sekcja deklaracji służy do deklarowania wszelkich publicznych sekcji kodu, które pojawiają się w jednostce. W tym artykule wyjaśnimy interfejsy z perspektywy OOP.

Jeśli masz zamiar stworzyć solidną aplikację w taki sposób, aby twój kod był łatwy w utrzymaniu, wielokrotnego użytku i elastyczny OOP natura Delphi pomoże ci przejechać pierwsze 70% trasy. Zdefiniowanie i wdrożenie interfejsów pomoże z pozostałymi 30%.

Klasy abstrakcyjne

Możesz myśleć o interfejsie jako o klasie abstrakcyjnej z usuniętą całą implementacją i usuniętym wszystkim, co nie jest publiczne. Klasa abstrakcyjna w Delfy to klasa, której nie można utworzyć - nie można utworzyć obiektu z klasy oznaczonej jako abstrakcyjna.

Rzućmy okiem na przykładową deklarację interfejsu:

rodzaj
IConfigChanged = berło[„{0D57624C-CDDE-458B-A36C-436AE465B477}”]
procedura ApplyConfigChange;
koniec;
instagram viewer

The IConfigChanged jest interfejsem. Interfejs jest zdefiniowany podobnie do klasy, słowo kluczowe „interfejs” jest używane zamiast „klasa”. Wartość Guid występująca po słowie kluczowym interfejsu jest używana przez kompilator do jednoznacznej identyfikacji interfejsu. Aby wygenerować nową wartość GUID, po prostu naciśnij Ctrl + Shift + G w Delphi IDE. Każdy zdefiniowany interfejs wymaga unikalnej wartości Guid.

Interfejs w OOP definiuje abstrakcję - szablon dla faktycznej klasy, która zaimplementuje interfejs - która zaimplementuje metody zdefiniowane przez interfejs. Interfejs tak naprawdę nic nie robi, ma jedynie sygnaturę interakcji z innymi (implementującymi) klasami lub interfejsami.

Implementacja metod (funkcje, procedury i właściwość Metody Get / Set) odbywa się w klasie, która implementuje interfejs. W definicji interfejsu nie ma sekcji zakresu (prywatny, publiczny, opublikowany itp.), Wszystko jest publiczne. Typ interfejsu może definiować funkcje, procedury (które ostatecznie staną się metodami klasy implementującej interfejs) i właściwości. Kiedy interfejs definiuje właściwość, musi definiować metody get / set - interfejsy nie mogą definiować zmiennych.

Podobnie jak w przypadku klas, interfejs może dziedziczyć z innych interfejsów.

rodzaj
IConfigChangedMore = berło(IConfigChanged)
procedura ApplyMoreChanges;
koniec;

Programowanie

Większość programistów Delphi, kiedy myśli o interfejsach, myśli o programowaniu COM. Jednak interfejsy to tylko funkcja OOP języka - nie są one powiązane konkretnie z COM. Interfejsy można definiować i implementować w aplikacji Delphi bez dotykania COM.

Realizacja

Aby zaimplementować interfejs, musisz dodać nazwę interfejsu do instrukcji class, jak w:

rodzaj
TMainForm = klasa(TForm, IConfigChanged)
publiczny
procedura ApplyConfigChange;
koniec;

W powyższym kodzie formularz Delphi o nazwie „MainForm” implementuje interfejs IConfigChanged.

Ostrzeżenie: gdy klasa implementuje interfejs, musi zaimplementować wszystkie swoje metody i właściwości. W przypadku niepowodzenia / zapomnienia zaimplementowania metody (na przykład: ApplyConfigChange) wystąpi błąd czasu kompilacji „E2003 Niezadeklarowany identyfikator:„ ApplyConfigChange ”” wystąpi.
Ostrzeżenie: jeśli spróbujesz określić interfejs bez wartości GUID, otrzymasz: „Typ E2086„ IConfigChanged ”nie jest jeszcze całkowicie zdefiniowany”.

Przykład

Rozważ aplikację MDI, w której użytkownik może jednocześnie wyświetlić kilka formularzy. Gdy użytkownik zmienia konfigurację aplikacji, większość formularzy musi zaktualizować swój ekran - pokaż / ukryj niektóre przyciski, zaktualizuj podpisy etykiet itp. Potrzebny byłby prosty sposób powiadamiania wszystkich otwartych formularzy o zmianie konfiguracji aplikacji. Idealnym narzędziem do pracy był interfejs.

Każdy formularz, który musi zostać zaktualizowany, gdy zmiany konfiguracji zaimplementują IConfigChanged. Ponieważ ekran konfiguracji jest wyświetlany modalnie, po zamknięciu następnego kodu zapewnia, że ​​wszystkie formularze implementacyjne IConfigChanged zostaną powiadomione, a ApplyConfigChange zostanie wywołany:

procedura DoConfigChange ();
var
cnt: liczba całkowita;
icc: IConfigChanged;
zaczynać
dla cnt: = 0 do -1 + ekran. FormCount robić
zaczynać
gdyby Obsługuje (ekran. Forms [cnt], IConfigChanged, icc) następnie
icc. ApplyConfigChange;
koniec;
koniec;

Wspiera funkcjonować (zdefiniowane w Sysutils.pas) wskazuje, czy dany obiekt lub interfejs obsługuje określony interfejs. Kod iteruje się po ekranie. Kolekcja formularzy (obiektu TScreen) - wszystkie formularze aktualnie wyświetlane w aplikacji. Jeśli formularz Ekran. Formularze [cnt] obsługuje interfejs, obsługuje interfejs dla ostatniego parametru parametru i zwraca wartość true.

Dlatego jeśli formularz implementuje IConfigChanged, zmiennej icc można użyć do wywołania metod interfejsu zaimplementowanych przez formularz. Pamiętaj oczywiście, że każda forma może mieć własną inną implementację procedury ApplyConfigChange.

Przodkowie

Każda klasa zdefiniowana w Delphi musi mieć przodka. TObject jest ostatecznym przodkiem wszystkich obiektów i komponentów. Powyższy pomysł dotyczy również interfejsów. Interfejs II jest klasą bazową dla wszystkich interfejsów. IInterface definiuje 3 metody: QueryInterface, _AddRef i _Release.

Oznacza to, że nasz IConfigChanged ma również te 3 metody, ale ich nie wdrożyliśmy. Wynika to z faktu, że TForm dziedziczy po TComponent, który już zaimplementował interfejs II dla Ciebie! Jeśli chcesz zaimplementować interfejs w klasie dziedziczącej po TObject, upewnij się, że twoja klasa dziedziczy po TInterfacedObject. Ponieważ TInterfacedObject jest TObject implementującym IInterface. Na przykład:

TMyClass = klasa(TInterfacedObject, IConfigChanged)
procedura ApplyConfigChange;
koniec;

Podsumowując, IUnknown = IInterface. IUnknown jest dla COM.