DI czyli Dependency Injection (wstrzykiwanie zależności) to technika usuwająca zależności pomiędzy komponentami. Definicję można znaleźć np. w wikipedi czy też w wielu innych źródłach, jednak dla osób wolących zobaczyć w przykładzie o co chodzi pokażę na przykładzie w jaki sposób można skorzystać z dobrodziejstwa DI.
W celu zaprezentowania działania DI stworzymy prostą aplikację konsolową. Będzie to prosta klasa realizująca wzorzec Repository:
Code:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int BirthYear { get; set; }
public override string ToString()
{
return string.Format("{0} {1} {2}", FirstName, LastName, BirthYear);
}
}
Code:
public interface IRepository<T>
{
void Add(T entity);
void Remove(T entity);
IEnumerable<T> GetElements();
}
Code:
public interface IPersonRepository : IRepository<Person>
{
}
Code:
public class PersonRepository : IPersonRepository
{
private List<Person> lPersonList = new List<Person>();
public void Add(Person entity)
{
lPersonList.Add(entity);
}
public void Remove(Person entity)
{
lPersonList.Remove(entity);
}
public IEnumerable<Person> GetElements()
{
return lPersonList;
}
}
Funkcja main będzie zawierać następujący kod:
Code:
static void Main(string[] args)
{
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IPersonRepository, PersonRepository>();
var personRepository = unityContainer.Resolve<IPersonRepository>();
personRepository.Add(new Person {FirstName = "Jacek", BirthYear = 2000, LastName = "Kowalski"});
foreach (var person in personRepository.GetElements())
{
Console.WriteLine(person);
}
}
Na początku tworzymy nasz kontener. Następnie następuje rejestracja interfejsu wraz z implementacją. Zabieg ten mówi: jeżeli użytkownik zażąda zwrócenia obiektu implementującego IPersonRepository - użytkownik otrzyma konkretną implementację w postaci obiektu klasy PersonRepository.
Następnie następuje pobranie obiektu na podstawie interfejsu - Resolve. Użytkownikowi zostaje zwrócony obiekt klasy PersonRepository na którym operuje jak na zwykłym obiekcie.
Przykład przedstawiony powyżej nie jest wymyślnym przykładem i nie obrazuje możliwości jakie daje DI w bardziej złożonym projekcie. Dlatego spróbujemy trochę bardziej skomplikować przykład:
Do naszego repozytorium dodamy interfejs odpowiedzialny za obliczanie całkowitego wynagrodzenia na podstawie wymyślonego wzoru:
Code:
public interface IEducationalYears
{
int EducationYears(Person persons);
}
Code:
public class EducationalYears : IEducationalYears
{
public int EducationYears(Person person)
{
int sum = 0;
int age = DateTime.Now.Year - person.BirthYear;
sum += age > 18 ? 11 : age - 7;
return sum;
}
}
Code:
public interface IPersonRepository : IRepository<Person>
{
decimal CalculateTotalWage();
}
Code:
public class PersonRepository : IPersonRepository
{
private List<Person> lPersonList = new List<Person>();
private IEducationalYears _educationalYears;
public PersonRepository(IEducationalYears educationalYears)
{
_educationalYears = educationalYears;
}
public void Add(Person entity)
{
lPersonList.Add(entity);
}
public void Remove(Person entity)
{
lPersonList.Remove(entity);
}
public IEnumerable<Person> GetElements()
{
return lPersonList;
}
public decimal CalculateTotalWage()
{
decimal sum = decimal.Zero;
foreach (var person in lPersonList)
{
sum += _educationalYears.EducationYears(person) * 125;
}
return sum;
}
}
Code:
static void Main(string[] args)
{
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IPersonRepository, PersonRepository>();
unityContainer.RegisterType<IEducationalYears, EducationalYears>();
var personRepository = unityContainer.Resolve<IPersonRepository>();
personRepository.Add(new Person {FirstName = "Jacek", BirthYear = 2000, LastName = "Kowalski"});
foreach (var person in personRepository.GetElements())
{
Console.WriteLine(person);
}
Console.WriteLine("Totale wage: {0}", personRepository.CalculateTotalWage());
}
Jak widać w funkcji main dodaliśmy tylko linijki odpowiedzialne za wyświetlenie wartości wynagrodzenia oraz zarejestrowaliśmy nowy typ w kontenerze.
Dzięki temu nie musimy w konstruktorze podawać konkretnego obiektu. Zaleta ta daje nam niezależność w przypadku rozszerzania funkcjonalności klas. Wystarczy że w konstruktorze dodamy odpowiednie obiekty, a w kontenerze zarejestrujemy nowe typy.
http://pl.wikipedia.org/wiki/Wstrzykiwanie_zale%C5%BCno%C5%9Bci
Brak komentarzy:
Prześlij komentarz