Wzorzec projektowy oprogramowania - Software design pattern

W inżynierii oprogramowania , wykorzystując wzorzec projektowania oprogramowania jest ogólnym, wielokrotnego użytku rozwiązanie problemu występującego powszechnie w danym kontekście, w projektowaniu oprogramowania . Nie jest to gotowy projekt, który można przekształcić bezpośrednio w kod źródłowy lub kod maszynowy . Jest to raczej opis lub szablon rozwiązania problemu, który można wykorzystać w wielu różnych sytuacjach. Wzorce projektowe to sformalizowane najlepsze praktyki, które programista może wykorzystać do rozwiązywania typowych problemów podczas projektowania aplikacji lub systemu.

Wzorce projektowe zorientowane obiektowo zazwyczaj pokazują relacje i interakcje między klasami lub obiektami , bez określania końcowych klas aplikacji lub obiektów, które są zaangażowane. Wzorce, które implikują zmienny stan, mogą być nieodpowiednie dla funkcjonalnych języków programowania . Niektóre wzorce mogą być niepotrzebne w językach, które mają wbudowaną obsługę rozwiązywania problemu, który próbują rozwiązać, a wzorce obiektowe niekoniecznie są odpowiednie dla języków niezorientowanych obiektowo.

Wzorce projektowe mogą być postrzegane jako ustrukturyzowane podejście do programowania komputerowego pośredniczące między poziomami paradygmatu programowania a konkretnym algorytmem .

W badaniu przeglądowym z 2020 r. Wedyan i Abufakher badają wzorce projektowe i jakość oprogramowania i dochodzą do wniosku: „Nasze badanie wykazało, że badania podstawowe dostarczają empirycznych dowodów na pozytywny wpływ dokumentacji wystąpień wzorców projektowych na zrozumienie programu, a tym samym na łatwość utrzymania. Choć wynik ten nie dziwi, ma jednak dwie przesłanki: po pierwsze, programiści powinni włożyć większy wysiłek w dodanie takiej dokumentacji, nawet w postaci prostych komentarzy w kodzie źródłowym.Po drugie, porównując wyniki różnych badań, należy wziąć pod uwagę efekt dokumentacji."

Historia

Wzory pochodzi jako koncepcji architektonicznej przez Christopher Alexander Już w 1977 roku (cf "Wzór ulicach," Journal of AIP, wrzesień 1977, t. 32, nr 3, s. 273-278). W 1987 roku Kent Beck i Ward Cunningham rozpoczęli eksperymentowanie z pomysłem zastosowania wzorców do programowania – w szczególności języków wzorców – i zaprezentowali swoje wyniki na konferencji OOPSLA w tym samym roku. W następnych latach Beck, Cunningham i inni kontynuowali tę pracę.

Wzorce projektowe zyskały popularność w informatyce po publikacji książki Design Patterns: Elements of Reusable Object-Oriented Software w 1994 roku przez tak zwaną „Gang of Four” (Gamma et al.), często określaną skrótem „GoF”. W tym samym roku odbyła się pierwsza Konferencja Języki Wzorców Programowania , a rok później powstało Repozytorium Wzorców Portland do dokumentacji wzorców projektowych. Zakres terminu pozostaje kwestią sporną. Godne uwagi książki z gatunku wzorców projektowych obejmują:

  • Gamma, Ericha ; Helm, Ryszard ; Johnsona, Ralpha ; Vlissides, John (1995). Wzorce projektowe: elementy oprogramowania obiektowego wielokrotnego użytku . Addisona-Wesleya . Numer ISBN 978-0-201-63361-0.
  • Brinch Hansen, Per (1995). Studia z informatyki: paradygmaty programowania równoległego . Sala Prezydencka. Numer ISBN 978-0-13-439324-7.
  • Buschmann, Frank ; Meunier, Regina; Rohnert, Hans; Sommerlad, Piotr (1996). Architektura oprogramowania zorientowana na wzorce, tom 1: System wzorców . John Wiley & Synowie. Numer ISBN 978-0-471-95869-7.
  • Beck, Kent (1997). Wzorce najlepszych praktyk Smalltalk . Sala Prezydencka. Numer ISBN 978-0134769042.
  • Schmidt, Douglas C .; Stal, Michał; Rohnert, Hans; Buschmann, Frank (2000). Architektura oprogramowania zorientowana na wzorce, tom 2: Wzorce dla obiektów współbieżnych i sieciowych . John Wiley & Synowie. Numer ISBN 978-0-471-60695-6.
  • Fowler, Martin (2002). Wzorce architektury aplikacji korporacyjnych . Addisona-Wesleya . Numer ISBN 978-0-321-12742-6.
  • Hohpe, Gregor; Woolf, Bobby (2003). Wzorce integracji w przedsiębiorstwie: projektowanie, budowanie i wdrażanie rozwiązań komunikacyjnych . Addisona-Wesleya . Numer ISBN 978-0-321-20068-6.
  • Freeman, Eric T.; Robson, Elisabeth; Bates, Bert; Sierra, Kathy (2004). Pierwsze wzorce projektowe . O'Reilly Media . Numer ISBN 978-0-596-00712-6.

Choć wzorce projektowe stosowane są praktycznie od dawna, formalizacja koncepcji wzorców projektowych przeciągała się przez kilka lat.

Ćwiczyć

Wzorce projektowe mogą przyspieszyć proces opracowywania, zapewniając przetestowane, sprawdzone paradygmaty programistyczne. Efektywne projektowanie oprogramowania wymaga rozważenia kwestii, które mogą pojawić się dopiero na późniejszym etapie wdrożenia. Świeżo napisany kod może często zawierać ukryte, subtelne problemy, których wykrycie wymaga czasu, które czasami mogą powodować poważne problemy w przyszłości. Ponowne wykorzystanie wzorców projektowych pomaga zapobiegać takim subtelnym problemom, a także poprawia czytelność kodu dla programistów i architektów, którzy znają wzorce.

Aby osiągnąć elastyczność, wzorce projektowe zwykle wprowadzają dodatkowe poziomy niebezpośredniości , co w niektórych przypadkach może komplikować wynikowe projekty i obniżać wydajność aplikacji.

Z definicji wzorzec musi być zaprogramowany od nowa w każdej aplikacji, która go używa. Ponieważ niektórzy autorzy postrzegają to jako krok wstecz od ponownego wykorzystania oprogramowania dostarczanego przez komponenty , badacze pracowali nad przekształceniem wzorców w komponenty. Meyer i Arnout byli w stanie zapewnić pełną lub częściową komponentyzację dwóch trzecich wzorców, których próbowali.

Techniki projektowania oprogramowania są trudne do zastosowania w szerszym zakresie problemów. Wzorce projektowe dostarczają ogólnych rozwiązań, udokumentowanych w formacie, który nie wymaga szczegółów związanych z konkretnym problemem.

Struktura

Wzorce projektowe składają się z kilku sekcji (patrz § Dokumentacja poniżej). Szczególnie interesujące są sekcje Struktura, Uczestnicy i Współpraca. Te sekcje opisują motyw projektowy : prototypową mikroarchitekturę, którą programiści kopiują i dostosowują do swoich konkretnych projektów, aby rozwiązać powtarzający się problem opisany przez wzorzec projektowy. Mikroarchitektura to zbiór składników programu (np. klas, metod...) i ich relacji. Deweloperzy wykorzystują wzorzec projektowy, wprowadzając w swoich projektach tę prototypową mikroarchitekturę, co oznacza, że ​​mikroarchitektury w swoich projektach będą miały strukturę i organizację zbliżoną do wybranego motywu projektowego.

Wzorce specyficzne dla domeny

Podjęto również wysiłki w celu skodyfikowania wzorców projektowych w poszczególnych domenach, w tym wykorzystania istniejących wzorców projektowych oraz wzorców projektowych specyficznych dla danej domeny. Przykłady obejmują wzorce projektowe interfejsu użytkownika , wizualizację informacji , bezpieczny projekt, „bezpieczną użyteczność”, projektowanie stron internetowych i projektowanie modeli biznesowych.

Coroczna konferencja Pattern Languages ​​of Programming zawiera wiele przykładów wzorców specyficznych dla danej dziedziny.

Klasyfikacja i lista

Wzorce projektowe zostały pierwotnie podzielone na 3 podklasyfikacje w oparciu o rodzaj problemu, który rozwiązują. Wzorce kreacyjne dają możliwość tworzenia obiektów w oparciu o wymagane kryterium i w kontrolowany sposób. Wzorce strukturalne polegają na organizowaniu różnych klas i obiektów w celu utworzenia większych struktur i zapewnienia nowej funkcjonalności. Wreszcie wzorce behawioralne polegają na identyfikowaniu wspólnych wzorców komunikacji między obiektami i realizacji tych wzorców.

Wzorce twórcze

Nazwa Opis We wzorcach projektowych W kodzie kompletny Inne
Fabryka abstrakcyjna Zapewnij interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez określania ich konkretnych klas. tak tak Nie dotyczy
Budowniczy Oddziel budowę złożonego obiektu od jego reprezentacji, umożliwiając tym samym procesowi budowy tworzenie różnych reprezentacji. tak Nie Nie dotyczy
Wstrzykiwanie zależności Klasa akceptuje obiekty, których wymaga od iniektora, zamiast tworzyć je bezpośrednio. Nie Nie Nie dotyczy
Metoda fabryczna Zdefiniuj interfejs do tworzenia pojedynczego obiektu, ale pozwól podklasom zdecydować, którą klasę utworzyć. Factory Method pozwala klasie odroczyć tworzenie instancji do podklas. tak tak Nie dotyczy
Inicjalizacja leniwa Taktyka opóźniania tworzenia obiektu, obliczania wartości lub innego kosztownego procesu do czasu, gdy jest to potrzebne po raz pierwszy. Ten wzorzec pojawia się w katalogu GoF jako „wirtualny serwer proxy”, strategia implementacji wzorca serwera proxy . Nie Nie PoEAA
Multiton Upewnij się, że klasa ma tylko nazwane instancje i zapewnij do nich globalny punkt dostępu. Nie Nie Nie dotyczy
Pula obiektów Unikaj kosztownego pozyskiwania i uwalniania zasobów poprzez recykling przedmiotów, które nie są już używane. Można uznać za uogólnienie wzorców puli połączeń i puli wątków . Nie Nie Nie dotyczy
Prototyp Określ rodzaje obiektów do utworzenia za pomocą instancji prototypowej i twórz nowe obiekty ze „szkieletu” istniejącego obiektu, zwiększając w ten sposób wydajność i ograniczając do minimum zużycie pamięci. tak Nie Nie dotyczy
Pozyskiwanie zasobów to inicjalizacja (RAII) Upewnij się, że zasoby są odpowiednio uwalniane, wiążąc je z żywotnością odpowiednich obiektów. Nie Nie Nie dotyczy
Singel Upewnij się, że klasa ma tylko jedną instancję i zapewnij globalny punkt dostępu do niej. tak tak Nie dotyczy

Wzory strukturalne

Nazwa Opis We wzorcach projektowych W kodzie kompletny Inne
Adapter , opakowanie lub tłumacz Konwertuj interfejs klasy na inny interfejs, którego oczekują klienci. Adapter umożliwia współdziałanie klas, które nie mogłyby działać w inny sposób z powodu niezgodnych interfejsów. Odpowiednikiem wzorca integracji przedsiębiorstwa jest translator. tak tak Nie dotyczy
Most Odłącz abstrakcję od jej implementacji, umożliwiając tym dwóm niezależną zmianę. tak tak Nie dotyczy
Złożony Komponuj obiekty w struktury drzewiaste, aby reprezentować hierarchie części-całości. Composite pozwala klientom na jednolite traktowanie poszczególnych obiektów i kompozycji obiektów. tak tak Nie dotyczy
Dekorator Dynamicznie dołączaj dodatkowe obowiązki do obiektu, zachowując ten sam interfejs. Dekoratory zapewniają elastyczną alternatywę dla podklas w celu rozszerzenia funkcjonalności. tak tak Nie dotyczy
Obiekt rozszerzenia Dodawanie funkcjonalności do hierarchii bez zmiany hierarchii. Nie Nie Zwinne tworzenie oprogramowania, zasady, wzorce i praktyki
Fasada Zapewnij ujednolicony interfejs zestawowi interfejsów w podsystemie. Fasada definiuje interfejs wyższego poziomu, który ułatwia korzystanie z podsystemu. tak tak Nie dotyczy
Waga lotna Użyj udostępniania, aby wydajnie obsługiwać dużą liczbę podobnych obiektów. tak Nie Nie dotyczy
Przedni kontroler Wzorzec odnosi się do projektowania aplikacji internetowych. Zapewnia scentralizowany punkt wejścia do obsługi wniosków. Nie Nie

Wzorce J2EE PoEAA

Znacznik Pusty interfejs do kojarzenia metadanych z klasą. Nie Nie Efektywna Java
Moduł Zgrupuj kilka powiązanych elementów, takich jak klasy, singletony, metody, używane globalnie, w jedną encję pojęciową. Nie Nie Nie dotyczy
Pełnomocnik Podaj odpowiednik lub symbol zastępczy dla innego obiektu, aby kontrolować dostęp do niego. tak Nie Nie dotyczy
Bliźniak Twin umożliwia modelowanie wielokrotnego dziedziczenia w językach programowania, które nie obsługują tej funkcji. Nie Nie Nie dotyczy

Wzorce zachowań

Nazwa Opis We wzorcach projektowych W kodzie kompletny Inne
Tablica szkolna Wzór sztucznej inteligencji do łączenia różnych źródeł danych (patrz system tablic ) Nie Nie Nie dotyczy
Łańcuch odpowiedzialności Unikaj łączenia nadawcy żądania z jego odbiorcą, dając więcej niż jednemu obiektowi szansę na obsługę żądania. Połącz obiekty odbierające i przekaż żądanie wzdłuż łańcucha, aż obiekt je obsłuży. tak Nie Nie dotyczy
Komenda Hermetyzuj żądanie jako obiekt, umożliwiając w ten sposób parametryzację klientów z różnymi żądaniami oraz kolejkowanie lub rejestrowanie żądań. Pozwala również na obsługę operacji cofalnych. tak Nie Nie dotyczy
Interpretator Mając dany język, zdefiniuj reprezentację jego gramatyki wraz z tłumaczem, który używa reprezentacji do interpretacji zdań w języku. tak Nie Nie dotyczy
Iterator Umożliwiają sekwencyjny dostęp do elementów obiektu zagregowanego bez ujawniania jego podstawowej reprezentacji. tak tak Nie dotyczy
Mediator Zdefiniuj obiekt, który zawiera sposób interakcji zestawu obiektów. Mediator promuje luźne sprzężenie , uniemożliwiając wyraźne odwoływanie się obiektów do siebie i umożliwia niezależne zmienianie ich interakcji. tak Nie Nie dotyczy
Memento Bez naruszania enkapsulacji, przechwyć i uzewnętrznij stan wewnętrzny obiektu, umożliwiając przywrócenie go do tego stanu później. tak Nie Nie dotyczy
Obiekt zerowy Unikaj odwołań o wartości null, podając obiekt domyślny. Nie Nie Nie dotyczy
Obserwator lub Publikuj/subskrybuj Zdefiniuj zależność jeden-do-wielu między obiektami, w której zmiana stanu jednego obiektu powoduje automatyczne powiadamianie i aktualizację wszystkich jego zależnych. tak tak Nie dotyczy
Sługa Zdefiniuj wspólną funkcjonalność dla grupy klas. Wzorzec podrzędny jest również często nazywany klasą pomocniczą lub implementacją klasy użytkowej dla danego zestawu klas. Klasy pomocnicze generalnie nie mają obiektów, dlatego mają wszystkie statyczne metody, które działają na różnych rodzajach obiektów klas. Nie Nie Nie dotyczy
Specyfikacja Logika biznesowa z możliwością rekombinacji w sposób logiczny . Nie Nie Nie dotyczy
Stan Pozwól obiektowi zmienić swoje zachowanie, gdy zmieni się jego stan wewnętrzny. Obiekt pojawi się, aby zmienić swoją klasę. tak Nie Nie dotyczy
Strategia Zdefiniuj rodzinę algorytmów, zamknij każdy z nich i uczyń je wymiennymi. Strategia pozwala algorytmowi różnić się niezależnie od klientów, którzy go używają. tak tak Nie dotyczy
Metoda szablonowa Zdefiniuj szkielet algorytmu w operacji, odkładając niektóre kroki do podklas. Metoda szablonowa pozwala podklasom przedefiniować pewne kroki algorytmu bez zmiany struktury algorytmu. tak tak Nie dotyczy
Gość Reprezentują operację, która ma być wykonana na elementach struktury obiektu. Odwiedzający pozwala na zdefiniowanie nowej operacji bez zmiany klas elementów, na których operuje. tak Nie Nie dotyczy

Wzorce współbieżności

Nazwa Opis W POSA2 Inne
Obiekt aktywny Oddziela wykonanie metody od wywołania metody, która znajduje się we własnym wątku kontroli. Celem jest wprowadzenie współbieżności za pomocą asynchronicznego wywoływania metod i harmonogramu do obsługi żądań. tak Nie dotyczy
Baling Wykonaj akcję na obiekcie tylko wtedy, gdy obiekt jest w określonym stanie. Nie Nie dotyczy
Właściwości wiązania Łączenie wielu obserwatorów, aby wymusić synchronizację lub koordynację właściwości różnych obiektów. Nie Nie dotyczy
Oblicz jądro Te same obliczenia wiele razy równolegle, różniące się parametrami całkowitymi używanymi z nierozgałęziającą się matematyką wskaźnikową na współdzielone tablice, takie jak zoptymalizowane pod kątem GPU mnożenie macierzy lub splotowa sieć neuronowa . Nie Nie dotyczy
Podwójnie sprawdzone ryglowanie Zmniejszyć koszty uzyskania blokady, najpierw testując kryterium blokowania („wskazówkę dotyczącą blokady”) w niebezpieczny sposób; tylko wtedy, gdy to się powiedzie, rzeczywista logika blokowania będzie kontynuowana.

Może być niebezpieczny, gdy zostanie zaimplementowany w niektórych kombinacjach języka/sprzętu. Dlatego czasami może być uważany za antywzór .

tak Nie dotyczy
Asynchroniczny oparty na zdarzeniach Rozwiązuje problemy z asynchronicznym wzorcem, które występują w programach wielowątkowych. Nie Nie dotyczy
Zawieszenie strzeżone Zarządza operacjami, które wymagają zarówno uzyskania blokady, jak i spełnienia warunku wstępnego przed wykonaniem operacji. Nie Nie dotyczy
Dołączyć Join-pattern umożliwia pisanie programów współbieżnych, równoległych i rozproszonych poprzez przekazywanie komunikatów. W porównaniu z użyciem wątków i blokad jest to model programowania wysokiego poziomu. Nie Nie dotyczy
Zamek Jeden wątek nakłada „blokadę” na zasób, uniemożliwiając innym wątkom dostęp do niego lub jego modyfikację. Nie PoEAA
Wzorzec projektowy wiadomości (MDP) Umożliwia wymianę informacji (tj. komunikatów) między komponentami i aplikacjami. Nie Nie dotyczy
Monitoruj obiekt Obiekt, którego metody podlegają wzajemnemu wykluczeniu , co zapobiega błędnym próbom użycia go przez wiele obiektów w tym samym czasie. tak Nie dotyczy
Reaktor Obiekt reaktora zapewnia asynchroniczny interfejs do zasobów, które muszą być obsługiwane synchronicznie. tak Nie dotyczy
Blokada odczytu i zapisu Umożliwia współbieżny dostęp do odczytu do obiektu, ale wymaga wyłącznego dostępu do operacji zapisu. Do pisania może być używany podstawowy semafor, a mechanizm kopiowania przy zapisie może, ale nie musi być używany. Nie Nie dotyczy
Planista Jawnie kontroluj, kiedy wątki mogą wykonywać kod jednowątkowy. Nie Nie dotyczy
Pula wątków Szereg wątków jest tworzonych w celu wykonania szeregu zadań, które zwykle są zorganizowane w kolejce. Zazwyczaj zadań jest znacznie więcej niż wątków. Można uznać za szczególny przypadek wzorca puli obiektów . Nie Nie dotyczy
Przechowywanie specyficzne dla wątku Pamięć statyczna lub „globalna” lokalna dla wątku. tak Nie dotyczy
Bezpieczna współbieżność dzięki wyłącznej własności Unikanie potrzeby współbieżnych mechanizmów wykonawczych, ponieważ można udowodnić wyłączną własność. Jest to godna uwagi funkcja języka Rust, ale sprawdzanie w czasie kompilacji nie jest jedynym sposobem, programista często ręcznie projektuje takie wzorce w kodzie - pomijając użycie mechanizmu blokującego, ponieważ programista ocenia, że ​​dana zmienna nigdy nie działa do równoczesnego dostępu. Nie Nie dotyczy
Atomowe działanie procesora x86 i inne architektury procesorów CPU obsługują szereg instrukcji atomowych, które gwarantują bezpieczeństwo pamięci podczas modyfikowania i uzyskiwania dostępu do wartości pierwotnych (liczby całkowite). Na przykład dwa wątki mogą bezpiecznie zwiększać licznik. Te możliwości można również wykorzystać do implementacji mechanizmów dla innych wzorców współbieżności, jak powyżej. Język C# używa klasy Interlocked dla tych możliwości. Nie Nie dotyczy

Dokumentacja

Dokumentacja wzorca projektowego opisuje kontekst, w którym wzorzec jest używany, siły w kontekście, które wzorzec ma rozwiązać, oraz sugerowane rozwiązanie. Nie ma jednego, standardowego formatu dokumentowania wzorców projektowych. Raczej różne formaty były używane przez różnych autorów wzorców. Jednak według Martina Fowlera pewne formy wzorców stały się bardziej znane niż inne i w konsekwencji stały się wspólnym punktem wyjścia dla nowych prób pisania wzorców. Jednym z przykładów powszechnie używanego formatu dokumentacji jest format używany przez Ericha Gammę , Richarda Helma , Ralpha Johnsona i Johna Vlissidesa w ich książce Design Patterns . Zawiera następujące sekcje:

  • Nazwa i klasyfikacja wzoru: opisowa i niepowtarzalna nazwa, która pomaga w identyfikacji i odwoływaniu się do wzoru.
  • Intencja: Opis celu stojącego za wzorcem i powodu jego użycia.
  • Znany również jako: Inne nazwy wzorca.
  • Motywacja (siły): Scenariusz składający się z problemu i kontekstu, w którym można zastosować ten wzorzec.
  • Zastosowalność: Sytuacje, w których ten wzór jest użyteczny; kontekst wzorca.
  • Struktura: Graficzna reprezentacja wzoru. W tym celu można wykorzystać diagramy klas i diagramy interakcji .
  • Uczestnicy: Wykaz klas i obiektów użytych we wzorze oraz ich ról w projekcie.
  • Współpraca: opis interakcji klas i obiektów używanych we wzorcu.
  • Konsekwencje: opis wyników, skutków ubocznych i kompromisów spowodowanych użyciem wzorca.
  • Implementacja: opis implementacji wzorca; część rozwiązania wzoru.
  • Przykładowy kod: ilustracja przedstawiająca sposób użycia wzorca w języku programowania.
  • Znane zastosowania: Przykłady rzeczywistych zastosowań wzorca.
  • Powiązane wzorce: inne wzorce, które mają pewien związek z wzorcem; omówienie różnic między wzorem a podobnymi wzorami.

Krytyka

Zaobserwowano, że wzorce projektowe mogą być jedynie oznaką braku pewnych funkcji w danym języku programowania (np. Java czy C++ ). Peter Norvig demonstruje, że 16 z 23 wzorców w książce Design Patterns (która koncentruje się głównie na C++) jest uproszczonych lub wyeliminowanych (poprzez bezpośrednią obsługę języka) w Lisp lub Dylan . Powiązane obserwacje poczynili Hannemann i Kiczales, którzy zaimplementowali kilka z 23 wzorców projektowych przy użyciu języka programowania zorientowanego aspektowo (AspectJ) i wykazali, że zależności na poziomie kodu zostały usunięte z implementacji 17 z 23 wzorców projektowych i że zorientowane aspektowo programowanie może uprościć implementacje wzorców projektowych. Zobacz także esej Paula Grahama „Zemsta frajerów”.

Niewłaściwe użycie wzorców może niepotrzebnie zwiększać złożoność.

Zobacz też

Bibliografia

Dalsza lektura