Autor wpisu: sokzzuka, dodany: 24.05.2010 23:51, tagi: php
Dzisiejszy post będzie o moim własnonożnie zrobionym kontenerze IOC (inversion of control). Najpierw kilka słów, czym jest wzorzec IOC.
W wielkim uproszczeniu wzorzec IOC polega na przeniesieniu poza obiekt wszelkich funkcjonalności nie związanych bezpośrednio z jego przeznaczeniem. Celem jest:
- zdefiniowanie jasnych odpowiedzialności poszczególnych klas
- stworzeniem abstrakcji dzięki której zmiana jednego elementu systemu nie będzie wpływała na inne
- uniezależnienie się od implementacji poszczególnych części systemu
Tyle do IOC, natomiast kontener IOC jest specjalną klasą, która na nasz zlecenie konstruuje za nas obiekty, których potrzebujemy dbając o wszelkie zależności między nimi.
Realizacja wygląda w ten sposób, że deklaratywnie określamy jakie są zależności między obiektami i na podstawie naszego opisu całą techniczną stroną tworzenia obiektów zajmuje się kontener IOC.
Kontener wraz z przykładem użycia można ściągnąć z tąd (licencja BSD).
Mój kontener IOC składa się z dwóch podstawowych częsci:
- fabryka obiektów
- adaptery dla różnych formatów określania zależności między obiektami
Fabryka obiektów tworzy i zarządza obiektami biorąc pod uwagę czas ich istnienia. Zarządza obiektami, których stan trzymany jest przez całą sesję użytkownika jak i może ich stan być trzymany nieskończenie długo i dostępny między sesjami użytkowników ( do tego potrzebny jest mechanizm cache typu APC lub XCache z odpowiednim adapterem).
Co do adapterów to na dziś dzień stworzony jest jeden adapter, który czyta XML-e. Pokrótce o tym jak opisywać obiekty w tymże XML-u.
<object-config> <application> <!-- For now empty, objects declared here will be cached by APC or something similiar --> </application> <session> <object class="FooFoo"> <property name="someParameter">baz_foo</property> </object> </session> <request> <object class="Foo1"> <property name="param2">other_baz</property> <property name="param1">baz</property> </object> <object class="Foo2"> <property name="param2">baz_faz</property> <property name="param1">baz_baz</property> </object> <object class-match="/Foo[0-9]+/"> <property name="param3" type="class">@self</property> </object> <object class="Bar" id="FooBar"> <property type="class" name="param1">Foo1</property> <property type="const" name="param2">FooConst</property> <property type="id" name="param3">Foo2</property> <proxy class="FooProxy"/> </object> </request> </object-config>
Jak widać albo i nie . Stopień niżej od roota są trzy tagi – “application”, “session”, “request”, które grupują w sobie tagi object. Te trzy tagi określają czy stan obiektu będzie trwał dla sesji czy dla pojedynczego requestu czy wiecznie dla całej aplikacji.
Tagi object określają konfigurację poszczególnych obiektów. Kolejne właściwości obiektu ustawiamy za pomocą tagów “property”. Obowiązkowym atrybutem tagu “property” jest “name”, mówi on o nazwie parametru w konstruktorze lub nazwie settera przez który ma być wstrzyknięta właściwość obiektu. Dzięki temu rozwiązaniu, nie ma znaczenia w jakiej kolejności podamy właściwości, zawsze zostaną one właściwie wstrzyknięte.