8.03.20223 min

Rikam PalkarSoftware Engineer / .NET Fullstack

Jak zaimplementować wzorzec facade w C#

Sprawdź, jak zaimplementować popularny wzorzec projektowy krok po kroku.

Jak zaimplementować wzorzec facade w C#


Po co nam Facade design pattern?

Przyjrzyj się uważnie poniższej ilustracji. Klasa po prawej stronie potrzebuje czterech metod, które należą do klasy po lewej stronie. Jednak aby określić, do których z czterech metod musimy uzyskać dostęp, prawdopodobnie będziemy musieli pogrzebać w organizacji wewnętrznej najbardziej wysuniętej na lewo ClassA. Albo… istnieje lepsze rozwiązanie!

Mogę po prostu umieścić fasadę pomiędzy moimi klasami. Teraz ta fasada ma wewnętrzne odniesienie do ClassA i organizuje wywołania w imieniu klasy Program. Używamy klasy fasady, która zawiera ClassAi udostępnia tylko te metody, które są potrzebne naszemu programowi. Możemy używać bardziej znaczących nazw metod, a ponadto nasz program będzie rozmawiał tylko z fasadą, nie wiedząc nic o ClassA.

Skalowalny i złożony projekt zawiera oczywiście setki klas. Ten wzorzec pomaga naszej klasie wywołującej, dzięki skupieniu się na tym, co jest w tym momencie ważne, zamiast przeglądania wszystkiego (abstrakcja w programowaniu obiektowym).

Załóżmy, że chcemy zaimplementować klasę dla smartfona, która ma 3 specyfikacje: procesor, pamięć (RAM, ROM) i wyświetlacz. Nasza implementacja może przedstawiać się następująco:


Listing 1: klasa Processor

namespace FacadeDesignPattern  
{  
    public class Processor  
    {  
        public void DisplayProcessor()  
        {  
            System.Console.WriteLine("Snapdragon 635");  
        }  
  
    }  
} 


Listing 2: klasa Memory

namespace FacadeDesignPattern  
{  
    public class Memory  
    {  
        public void AssembleMemory()  
        {  
            System.Console.WriteLine("8GB RAM + 128GB ROM");  
        }  
    }  
}  


Listing 3: klasa Display:

namespace FacadeDesignPattern  
{  
    public class Display  
    {  
        public void AssembleDisplay()  
        {  
            System.Console.WriteLine("Retina Display");  
        }  
    }  
}  


Listing 4: klasa wywołująca, klasa SmartPhone:

  
namespace FacadeDesignPattern  
{  
    class SmartPhone  
    {  
        static void Main(string[] args)  
        {  
            Console.WriteLine("One Plus 8");  
            //calling processor  
            Processor processor = new Processor();  
            processor.AssembleProcessor();  
  
            //calling memory  
            Memory memory = new Memory();  
            memory.AssembleMemory();  
  
            //calling display  
            Display display = new Display();  
            display.AssembleDisplay();  
        }  
    }  
}


Jest to prosty problem, ale ponieważ smartfony muszą podążać za najnowszymi trendami i innowacjami, trzeba będzie dodać więcej klas dla każdej funkcji.

Aby ponownie zaimplementować smartPhone, trzeba przebrnąć przez wszystkie te klasy, a tutaj mamy tylko 3: Display, Memory, Processor. W prawdziwym projekcie, jak już wspomniałem, mielibyśmy do czynienia z setkami klas, co utrudnia znalezienie tych potrzebnych do implementacji nowego smartPhone.

Jesteśmy w stanie dodać warstwę pośrednią, która będzie odgrywała rolę fasady dla naszego smartfona i która zajmie się wszystkimi funkcjami niezbędnymi do stworzenia smartfona. Jeśli chcemy, aby nasz wzorzec był bardziej rozwinięty, możemy dodać interfejs, za pomocą którego nasza klasa smartPhone będzie wchodzić w interakcje.


Dlaczego interfejs? Dobre pytanie.

Ta abstrakcja pozwala programowi wywołującemu (w tym przypadku smartPhone) pracować wyłącznie z fasadą i tym samym uprościć nasz kod. Wprowadzenie w tym miejscu interfejsu naprawdę porządkuje sprawy dla programu żądającego i umożliwia łatwe dodawanie nowych klas fasady do bazowych klas serwisowych (więcej funkcji, więcej klas), które będą zmieniały się w przyszłości (bardziej zaawansowane klasy smartfonów).

Jeśli jutro na przykład wypuściłbym na rynek nowy smartfon z systemem Android 10 o nowej, wysokiej klasie specyfikacji, to mógłbym to osiągnąć poprzez interakcję z interfejsem.

Skoro już o tym mowa, zacznijmy pracę z Facade design pattern.

A gdyby tak umieścić procesor, pamięć i wyświetlacz za fasadą, aby smartfon nie musiał się martwić o powyższą złożoność?


Krok 1


Listing 5: Dodajmy interfejs ISmartPhoneFacade:

namespace FacadeDesignPattern  
{  
    interface ISmartPhoneFacade  
    {  
       void ShowSmartPhoneSpecifications();  
    }  
}


Krok 2


Listing 6: Teraz dodajmy klasę SmartPhoneFacade:

namespace FacadeDesignPattern  
{  
    public class SmartPhoneFacade : ISmartPhoneFacade  
    {  
        private Display display;  
        private Memory memory;  
        private Processor processor;  
  
        public SmartPhoneFacade() : this(new Display(), new Memory(), new Processor())  
        {  
  
        }  
        public SmartPhoneFacade(Display display, Memory memory, Processor processor)  
        {  
            this.memory = memory;  
            this.display = display;  
            this.processor = processor;  
        }  
        public void ShowSmartPhoneSpecifications()  
        {  
            display.AssembleDisplay();  
            memory.AssembleMemory();  
            processor.DisplayProcessor();  
        }  
    }  
}


Listing 7: Teraz spójrzmy nieco prościej na naszą klasę smartPhone:

using System;  
  
namespace FacadeDesignPattern  
{  
    class SmartPhone  
    {  
        static void Main(string[] args)  
        {  
            ISmartPhoneFacade smartPhone = new SmartPhoneFacade();  
            smartPhone.ShowSmartPhoneSpecifications();  
        } 
    }  
} 


Jeśli jutro pojawi się nowe urządzenie smartPhone, wystarczy, że utworzę nową fasadę, specyficzną dla funkcji smartPhone i dziedziczącą po interfejsie ISmartPhoneFacade. To jest właśnie siła abstrakcji w programowaniu obiektowym.

Uwaga: dodanie dodatkowej klasy może wydawać się kłopotliwe, ale w szerszej perspektywie jest to pomocne i właśnie w tym miejscu można zaprojektować klasy, które są luźno powiązane.

Mam szczerą nadzieję, że podobał Ci się ten artykuł i że zainspirował Cię do zastosowania zdobytej wiedzy w twoich własnych aplikacjach.


Oryginał tekstu w języku angielskim możesz przeczytać tutaj. 

<p>Loading...</p>