Konsultacje: wtorek, 1015 - 1145
| punkty | ocena |
| < 25 | ndst |
| 25-50 | dst |
| 50-75 | db |
| > 75 | bdb |
| Od kiedy | Do kiedy | Rozdziały |
|---|---|---|
| - | 13.04.2010 (włącznie) | 1.*, 2.* |
| - | 11.05.2010 (włącznie) | 3.1, 3.2 |
| - | 08.06.2010 (włącznie) | 3.3, 3.4, 3.5, 3.6 |
| - | do końca semestru | pozostałe |
2010-03-09
class SmtpFacade {
public void Send( string From, string To, string Subject, string Body, Stream Attachment, string AttachmentMimeType );
}
public class Person { }
public class PersonDataContext {
private Messenger _messenger = new Messenger();
private List _persons;
public void LoadPersons() {
_persons = ...;
}
public void NotifyPersons() {
foreach ( Person person in _persons )
_messenger.Nofify( person );
}
}
public class Messenger() {
public void Notify( Person person ) { }
}
Zrefaktoryzować ten przykład do wzorca Bridge tak, aby możliwe było wykorzystanie jednej z dwóch implementacji specjalizowanych klasy PersonDataContext, z których jedna
XmlPersonDataContext wczyta dane listy osobowej z pliku XML, a druga TextFilePersonDataContext wczyta dane listy osobowej z pliku tekstowego i złożenie wybranej implementacji
PersonDataContext z jedną z dwóch implementacji specjalizowanych klasy Messenger: FileMessenger, która utworzy plik o nazwie takiej jak identyfikator użytkownika z wiadomością w środku i
HttpPostMessenger, która użyje WebRequest do nawiązania połączenia ze stroną domową użytkownika.
public class ResourceManager {
public Bitmap CachedBitmap( string Name ) {
}
}
która utworzy nowy obiekt Bitmap z pliku o podanej nazwie i zapamięta go dla kolejnych wywołań. Do przechowywania stanu obiektów dla Flyweight najczęściej używa się kolekcji
asocjacyjnych.
Chciałbym żeby w trakcie ćwiczeń powstały co najmniej dwie implementacje, w dwóch zespołach, a następnie żebyśmy mogli wymienić się implementacjami, obejrzeć je, porównać i nawzajem skomentować.
public class SimpleContainer
{
public void RegisterType<T>( bool Singleton ) where T : class;
public void RegisterType<From, To>( bool Singleton ) where To : From;
public T Resolve<T>();
}
Podstawową metodą dla klienta kontenera jest metoda Resolve, której klient używa do tworzenia instancji obiektów:
SimpleContainer c = new SimpleContainer(); Foo fs = c.Resolve<Foo>();
SimpleContainer c = new SimpleContainer(); c.RegisterType<Foo>( true ); Foo f1 = c.Resolve<Foo>(); Foo f2 = c.Resolve<Foo>(); // f1 == f2Drugie przeciążenie służy do wyboru pożądanej implementacji klasy bazowej, abstrakcyjnej lub interfejsu:
SimpleContainer c = new SimpleContainer(); c.RegisterType<IFoo, Foo>( false ); IFoo f = c.Resolve<IFoo>(); // f ma typ Foo c.RegisterType<IFoo, Bar>( false ); IFoo g = c.Resolve<IFoo>(); // g ma typ BarUwaga. Nasza polityka zarządzania czasem życia obiektów przewiduje wyłącznie możliwość tworzenia obiektów ulotnych (w terminologii IoC mówi się transient) lub singetonów. W rzeczywistości bywa tak, że oprócz wbudowanych tych dwóch typowych polityk, może być zaimplementowana dowolna dodatkowa, np. w Unity jest tak. Uwaga. Jeżeli kontener nie ma zarejestrowanego typu interfejsu, a klient żąda obiektu typu interfejsu, powinien dowiedzieć się o tym jakimś rozsądnym wyjątkiem:
SimpleContainer c = new SimpleContainer(); IFoo f = c.Resolve<IFoo>(); // jakiś rozsądny wyjątek
public class SimpleContainer
{
...
public void RegisterInstance<T>( T Instance );
}
SimpleContainer c = new SimpleContainer;
IFoo foo1 = new Foo();
c.RegisterInstance<IFoo>( foo );
IFoo foo2 = c.Resolve<IFoo>();
// foo1 == foo2
class A
{
public A( B b ) { }
}
class B { }
SimpleContainer c = new SimpleContainer();
A a = c.Resolve<A>();
// kontener wykonstruuje A z wstrzykniętą instancją B
class X
{
public X( Y d, string s ) { };
}
class Y { }
SimpleContainer c = new SimpleContainer();
X x = c.Resolve<X>();
// wyjątek, string nie ma konstruktora bezparametrowego i nie da się rozwikłać żadnego z konstruktorów
// ... ale ....
c.RegisterInstance( "ala ma kota" ); // rejestruje instancję string, w C# parametr generyczny można opuścić w wywołaniu generycznym
X x = c.Resolve<X>();
// jest ok, zarejestrowano instancję string więc rozwikłanie konstruktora X jest możliwe
public class A {
public A( B b ) { }
[Dependency]
public C TheC { get; set; }
}
public class B {
}
public class C {
}
SimpleContainer c = new SimpleContainer();
A a = c.Resolve<A>();
// tworzy nową instancję A z B wstrzykniętym przez konstruktor i C wstrzykniętym przez właściwość
public class SimpleContainer
{
...
public void BuildUp<T>( T Instance );
}
SimpleContainer c = new SimpleContainer();
A theA = ....; // obiekt theA SKĄDŚ pochodzi, ale nie z kontenera
c.BuildUp( theA );
// wstrzykuje do theA zależności przez właściwości, tu: TheC
public delegate SimpleContainer ContainerProviderDelegate();
public class ServiceLocator {
public static void SetContainerProvider( ContainerProviderDelegate ContainerProvider ) {
...
}
public static ServiceLocator Current
{
get {
... singleton ...
}
}
public T GetInstance<T>();
}
// Przykład 1, rejestrowanie lokatora
SimpleContainer c = new SimpleContainer();
ContainerProviderDelegate containerProvider = () => c;
ServiceLocator.SetContainerProvider( containerProvider );
/* zapamiętano funkcję rozwikłującą referencję do kontenera - to zawsze będzie TEN sam kontener */
// Przykład 2, rejestrowanie lokatora
ContainerProviderDelegate containerProvider = () => new SimpleContainer();
ServiceLocator.SetContainerProvider( containerProvider );
/* zapamiętano funkcję rozwikłującą referencję do kontenera - to zawsze będzie NOWY kontener */
// Przykład 3, kod kliencki
class Foo
void Bar() {
IService service = ServiceLocator.Current.GetInstance<IService>();
// GetInstance używa zarejestrowanej metody do rozwikływania kontenera do pobrania kontenera i rozwikłania zależności
// Tym razem jednak IService nie musiało być wstrzykiwane
}
}
SimpleContainer c = new SimpleContainer(); c .RegisterType<Foo>( true ) .RegisterType<IBar, Baz>( false ) .RegisterInstance<IQux>( qux );
<?xml version="1.0"?> <configuration> <configSections> <section name="simpleIoCContainer" type="Uwr.SimpleIoC.SimpleContainerConfigurationSection" /> ... </configSections> ... <simpleIoCContainer> <resolvableTypes> <add type="Foo" singleton="true" /> <add type="IBar" mapsTo="Baz" /> /* brak atrybutu singleton oznacza singleton=false */ </resolvableTypes> </simpleIoCContainer>
SimpleContainer c = new SimpleContainer();
SimpleContainerConfigurationSection iocConfig =
(SimpleContainerConfigurationSection)ConfigurationManager.GetSection( "simpleIoCContainer" );
iocConfig.Configure( c );
int Abs( int n ) {
}
int Min( int[] tab ) {
}