{ Inversion of Control Dependency injection at Delphi for Loose Coupling İsmail KOCACAN 2012 } unit uMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type IDocument = interface // GUID oluşturmak için kısayol : Ctrl+Shift+G ['{44E273D9-3C17-4821-B791-31CDDCE6C6D8}'] procedure Parse; end; TBaseDocument = class abstract(TInterfacedObject) private FPath: string; FContent: string; public property Path: string read FPath write FPath; property Content: string read FContent write FContent; end; TXMLDocument = class(TBaseDocument, IDocument) public procedure Parse; end; TJSONDocument = class(TBaseDocument, IDocument) public procedure Parse; end; TDocumentParser = class private FDocument: IDocument; public constructor Create(aDocument: IDocument); procedure DoParse; end; TfrmMain = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmMain: TfrmMain; implementation {$R *.dfm} { TXMLDocument } procedure TXMLDocument.Parse; begin OutputDebugString('XML parseleme işlemi yapıldı.'); end; { TJSONDocument } procedure TJSONDocument.Parse; begin OutputDebugString('JSON parseleme işlemi yapıldı.'); end; { TDocumentParser } constructor TDocumentParser.Create(aDocument: IDocument); begin FDocument := aDocument; end; procedure TDocumentParser.DoParse; begin FDocument.Parse; end; procedure TfrmMain.FormCreate(Sender: TObject); var axmldocument: TXMLDocument; ajsondocument: TJSONDocument; aParser: TDocumentParser; begin axmldocument := TXMLDocument.Create; aParser := TDocumentParser.Create(axmldocument); aParser.DoParse; ajsondocument := TJSONDocument.Create; aParser := TDocumentParser.Create(ajsondocument); aParser.DoParse; end; end.TBaseDocument taban sınıfını, "IInterface" arayüzünün üyelerini implemente etmiş,
ve "TObject" sınıfın tüm özelliklerini bünyesinde barındıran "TInterfacedObject" sınıfından kalıtıyoruz.
"TBaseDocument" sınıfını "TInterfacedObject" sınıfından kalıtmamızın sebebi ise ;
Üst sınıflarda(TXMLDocument,TJSONDocument) "IDocument" arayüzünü implemente ederken
"IInterface" arayüzünün fonksiyonlarını da bizden implemente ettirmek istemesidir.
"TBaseDocument" sınıfından kalıtarak oluşturduğumuz her yeni sınıfın,"IInterface" arayüzünün methodlarını da, implemente ettirmek kullanışlı bir yöntem değil...
O Sebeble ; TBaseDocument taban sınıfımızı türetebileceğimiz,"IIInterface" arayüzünün fonksiyonlarını implemente etmiş,başka bir sınıf lazım.Bu ihtiyacı karşılayacak olan sınıfı kendimizde yazabilirdik fakat,
hali hazırda var olan "TInterfacedObject" ihtiyacımızı karşılıyor. "TBaseDocument" sınıfını TInterfacedObject sınıfından kalıtmamızın sebebi de budur.
"TXMLDocument" ve "TJSONDocument" sınıflarını "TBaseDocument" sınıfından türetiyoruz.
Ve "IDocument" arayüzünün methodlarını implemente ettiriyoruz.
Nitekim her yeni TBilmemneDocument nesnesinin Parse procedure'sinin gövdesinde farklı işlemler olacaktır.
Dependency injection prensibinin "Setter" procedure'ler ve Constructor methodlar ile uygulanadığını okumuştum.Tabiki bence sadece bunlarla sınırlı değil injection olayı...
Biz nesneleri dış dünyaya,o nesnenin üyeleri ile açtığımız için,bence sadece set edilebilen, bir property üzerinden de injection yapılabilir diye düşünüyorum...
injection kısmı ile daha kullanışlı yazım şekilleri aklımda var ama onlar bir daha ki sefere...
Dependency injection prensibin uygulandığı kısım ise "TDocumentParser" sınıfının yapılandırıcısında.
constructor Create(aDocument: IDocument);
Bu şekilde yazmakla derleyiciye şunu demiş oluyoruz.IDocument arayüzünde veya IDocument arayüzünü implemente etmiş bir sınıf, parametre olarak geçilebilir.Bu şekilde yazmak tipden bağımsız olduğu için, daha esnek bir kodlama oluyor.Nasıl yani? Esnek derken ?
Yani IDocument arayüzünü implemente etmiş,TBaseDocument sınıfında türeyen ,yeni yeni sınıflar yazıp,
TDocumentParser sınıfın yapılandırıcında hiçbir değişiklik yapmadan,bu yeni sınıfları parametre olarak geçebiliriz.Bu tipden bağımsız,soyutlama yöntemi ile yazım tarzıydı.
Şimdi birde soyutlamadan yazdığımızı düşünecek olursak;
constructor Create(aDocument: TXMLDocument); overload;
constructor Create(aDocument: TJSONDocument); overload;
Her yeni yazdığımız üst sınıfda(misal TBilmemneDocument) Parse methodunu çağırabilmemiz için,
constructor Create(aDocument: TBilmemneDocument); overload; gibi değişikliği veya başka bir yazım tarzını, "TDocumentParser" sınıfında yapmamız gerekecekti.
Rtti ve Dependency Injection ile ilgili aklımda bir senaryo da var.
Bir daha ki sefere...
Kaynak kodları(XE2) buradan indirebilirsiniz
Kaynak kodları(XE2) buradan indirebilirsiniz
Kaynaklar :
http://martinfowler.com/articles/injection.html
http://www.kodcu.com/2011/04/inversion-of-control-ioc-nedir/
Hiç yorum yok:
Yorum Gönder