Dla jednego konkretnego problemu w architekturze aplikacji, nad którą pracuję, interfejsy wydają się być dobrym rozwiązaniem. W szczególności niektóre "obiekty biznesowe" zależą od zestawu ustawień, które są pobierane z bazy danych w rzeczywistej aplikacji. Pozwalając obiektom biznesowym poprosić o interfejs (poprzez Inwersja sterowania), i pozwalając centralnego obiektu TDatabaseSettings
zaimplementować te interfejsy, pozwala na lepsze odizolowanie, a tym samym o wiele łatwiejsze testowanie jednostkowe.Omijanie (wyłączanie) Licznik odwołań Delphi dla interfejsów
Jednak w Delphi interfejsy wydają się pochodzić z, w tym przypadku, nieprzyjemnej premii: liczenie odwołań. Oznacza to, że jeśli zrobię coś takiego:
type
IMySettings = interface
function getMySetting: String;
end;
TDatabaseSettings = class(..., IMySettings)
//...
end;
TMyBusinessObject = class(TInterfacedObject, IMySettings)
property Settings: IMySettings read FSettings write FSettings;
end;
var
DatabaseSettings: TDatabaseSettings;
// global object (normally placed in a controller somewhere)
//Now, in some function...
O := TMyBusinessObject.Create;
O.Settings := DatabaseSettings;
// ... do something with O
O.Free;
na ostatniej linii (O.Free
) mój globalny DatabaseSettings
obiekt jest teraz również uwolniony od ostatniego odniesienia interfejs do niego (co zostało zawarte w O
) jest stracone !
Jednym z rozwiązań byłoby przechowywanie "globalnego" obiektu DatabaseSettings
za pomocą interfejsu; innym rozwiązaniem byłoby przesłonięcie referencyjnego mechanizmu liczącego dla klasy TDatabaseSettings
, więc mogę dalej zarządzać DatabaseSettings
jako normalnym obiektem (co jest dużo bardziej zgodne z resztą aplikacji).
Podsumowując, moje pytanie brzmi: w jaki sposób wyłączyć mechanizm liczenia odwołań do interfejsu dla konkretnej klasy?
udało mi się znaleźć kilka informacji, które sugeruje przesłanianie metod _AddRef
IInterface
i _Release
dla klasy (TDatabaseSettings
w przykładzie); czy ktokolwiek to zrobił?
Czy powiedziałbyś, że nie powinienem tego robić (myląc - tylko zły pomysł?) I znaleźć inne rozwiązanie problemu architektonicznego?
Wielkie dzięki!
Wielkie dzięki za bardzo obszerną odpowiedź, jest to bardzo doceniane! Tak, prawdopodobnie powinienem pomyśleć nieco więcej, zanim przejdę do ciemnej ścieżki wyłączania liczenia referencji. – onnodb
OK, testowałem to w D2009 i działało jak czar ;-). –
Czy mam rację, że twój przykład faktycznie nie wyłącza całkowicie liczenia referencji, ale zamiast tego powoduje, że licznik odwołań zaczyna się od 1? Sądzę, że można to osiągnąć poprzez jawne wywołanie "TMyInterfacedObject._AddRef" zaraz po utworzeniu obiektu, a następnie wykonanie "_Release", gdzie normalnie nazywacie "Free"? – onnodb