Artykuł

freeimages.com freeimages.com
kwi 02 2015
0

Wzorzec adapter - przykładowa implementacja w C#

Wiele mówi się o dobrych praktykach tworzenia kodu, używaniu wzorców projektowych i innych zmyślnych rozwiązań. W praktyce nie jest jednak tak kolorowo. Często terminy gonią, w kodzie pojawiają się klasy, których liczba linii liczona jest w setkach, a pośród nich znaleźć można wiele bezmyślnych powtórzeń oraz niepraktycznych interfejsów. Ale przecież obiecaliśmy sobie, że kiedyś to zmienimy, prawda?

Takie sytuacje lubią się mścić. Bardzo często musimy rozszerzać pewne istniejące rozwiązania. Pół biedy jeśli mamy dużo czasu na refaktoring. Gorzej jeśli go nam brakuje, bądź też rozpatrywany kod został już użyty w wielu różnych miejscach i jakiekolwiek zmiany w jego interfejsach nie wchodzę w ogóle w rachubę. Co zrobić w takiej sytuacji?

Wciąż możemy sięgnąć po wzorce projektowe, np. po tytułowy Adapter, który w pewnym sensie pozwoli na reużycie istniejącego rozwiązania.

Idea

Wzorzec adapter jest swego rodzaju wyjściem awaryjnym. Rozważmy pewien przykładowy scenariusz.

Mamy pewne rozwiązanie które działa produkcyjnie już pewien czas. Na kod zawarty w tym oprogramowaniu zapinają się zarówno metody wewnątrz naszego kodu jak tez rozwiązania klienta - jednym słowem ciężko jest tu cokolwiek zmienić.

Teraz wyobraźmy sobie drugi przypadek. Mam drugie, podobne rozwiązanie, które w pewnym sensie działa bardzo podobnie, aczkolwiek operuje na innym interfejsie. Nasze możliwości refaktoringu są mocno ograniczone - nie możemy zmienić istniejących sygnatur metod, ani wyprowadzić wspólnego interfejsu. Czy jest jakieś inne wyjście niż zduplikowanie problematycznego kodu? Na szczęście okazuje się że tak, a jest nim właśnie tytułowy wzorzec.

Adapter idealnie się nadaje do takich sytuacji, ponieważ pozwala on dopasować pewną klasę(y) do innego interfejsu, poprzez utworzenie prostej nakładki która implementuje ten właśnie interfejs. Wewnątrz takiej struktury (nazywamy ją adapterem), wywołujemy metody adaptowanego obiektu, który sam w sobie pozostaje nietknięty. Nie jest to rozwiązanie idealne, ale jest to jakaś opcja, w sytuacji gdy mamy ograniczone możliwości zmiany istniejącego kodu.

Przykład praktyczny

W celu lepszego przyswojenia wzorca, przedstawię krótki przykład praktyczny. Zacznijmy od kodu istniejącej klasy, którą będziemy chcieli zaadaptować do innego interfejsu:

public class SomeStrangeClass
{
    public void DoSomeStrangeThing(string info)
    {
        Console.WriteLine(info);
    }
}

Na potrzeby przykładu, kod tej klasy jest maksymalnie prosty. Spójrzmy teraz na docelowy interfejs:

public interface IListener
{
    void Notify(string msg);
}

Jak widać, w pewnym sensie mamy do czynienia z podobnym rozwiązaniem, aczkolwiek pojawiają się tutaj różne sygnatury. Na szczęście problem można łatwo rozwiązać klasą adapteru:

public class SomeStrangeClassAdapter : IListener
{
    private SomeStrangeClass adaptee = null;

    public SomeStrangeClassAdapter(SomeStrangeClass adaptee)
    {
        this.adaptee = adaptee;
    }

    public void Notify(string msg)
    {
        // Optionally - do something else
        this.adaptee.DoSomeStrangeThing(msg);
    }
}

Rozwiązanie jest całkiem oczywiste - tworzymy nową klasę, która operuje na bycie SomeStrangeClass, którego instancja zostaje przekazana jej w konstruktorze. Następnie wywołujemy poszczególne metody przykrywanej klasy wewnątrz metod opisanych w interfejsie - ot cała filozofia;-)

Zwieńczeniem całego przykładu będzie testowa klasa Program:

public class Program
{
    static void Main(string[] args)
    {
        SomeStrangeClass obj = new SomeStrangeClass();
        IListener listener = new SomeStrangeClassAdapter(obj);
        listener.Notify("Testowa wiadomość!!!");
        Console.ReadKey();
    }
}

W prosty sposób dostosowaliśmy istniejący kod, do nowego interfejsu. Oczywiście nie jest to końca czyste rozwiązanie, ale jest to pewne wyjście z w sytuacji w której możliwości refaktoringu są ograniczone.

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus