Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00119 005377 19042368 na godz. na dobę w sumie
Myślenie obiektowe w programowaniu. Wydanie V - książka
Myślenie obiektowe w programowaniu. Wydanie V - książka
Autor: Liczba stron: 208
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-6104-1 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> inne - programowanie
Porównaj ceny (książka, ebook (-30%), audiobook).

Burzliwy rozwój obiektowości nastąpił w połowie lat 90. wraz z upowszechnieniem się takich języków jak C++ czy Smalltalk. Obecnie programowanie zorientowane obiektowo wciąż jest jednym z najważniejszych paradygmatów projektowania. Łatwo zauważyć, że większość nowoczesnych języków programowania i technologii sieciowych opiera się na technikach obiektowych. Nieco trudniej jest dostrzec, że mimo szybkiego ewoluowania technik i języków programistycznych podstawowe pojęcia programowania obiektowego pozostają niezmienne i niezależne od jakiejkolwiek platformy. Początkujący programiści powinni więc poświęcić nieco czasu na zapoznanie się z tymi pojęciami i naukę czegoś, co można nazwać 'myśleniem obiektowym w programowaniu'.

Ta książka jest kolejnym, poprawionym i uzupełnionym wydaniem wyczerpującego wprowadzenia do programowania zorientowanego obiektowo. Jej głównym celem jest przedstawienie podstaw myślenia obiektowego i najważniejszych pojęć w tym zakresie. Wyjaśniono tu, w jaki sposób poprawnie posługiwać się dziedziczeniem i kompozycją, odróżniać agregację od asocjacji oraz zrozumieć różnice między interfejsem a implementacją. Szczególną uwagę zwrócono na technologie, które przetrwały próbę czasu ostatnich 20 lat i stały się rdzeniem koncepcji programowania obiektowego. Opisano też najważniejsze wzorce projektowe, wskazano techniki unikania zależności i zaprezentowano zasady zwane SOLID, których przestrzeganie pozwala tworzyć kod wysokiej jakości, zrozumiały i elastyczny.

Dzięki tej książce:

Techniki obiektowe. Zrozum, zanim zaimplementujesz!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: The Object-Oriented Thought Process (5th Edition) Tłumaczenie: Łukasz Piwko ISBN: 978-83-283-6104-1 Authorized translation from the English language edition, entitled OBJECT-ORIENTED THOUGHT PROCESS, THE, 5th Edition by WEISFELD, MATT, published by Pearson Education, Inc, publishing as Addison-Wesley Professional, Copyright © 2019 Pearson Education, Inc. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc. POLISH language edition published by Helion SA, Copyright © 2020. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Helion SA dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Helion SA nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Helion SA ul. Kościuszki 1c, 44-100 Gliwice tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/myobp5 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/myobp5.zip Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treści O autorze ................................................................................11 Podzi(cid:246)kowania ........................................................................11 Wst(cid:246)p .....................................................................................13 Rozdzia(cid:228) 1 Podstawowe poj(cid:246)cia obiektowo(cid:264)ci ...........................................17 Podstawowe poj(cid:246)cia ............................................................................17 Obiekty a stare systemy .......................................................................18 Programowanie obiektowe a proceduralne .............................................19 Zamiana podej(cid:264)cia proceduralnego na obiektowe ..................................23 Programowanie proceduralne ..........................................................23 Programowanie obiektowe ..............................................................23 Definicja obiektu .................................................................................24 Dane obiektu .................................................................................24 Zachowania obiektu .......................................................................24 Definicja klasy .....................................................................................28 Tworzenie obiektów ........................................................................28 Atrybuty .........................................................................................30 Metody ..........................................................................................30 Komunikaty ...................................................................................30 Modelowanie klas przy u(cid:276)yciu diagramów UML .......................................31 Hermetyzacja i ukrywanie danych ..........................................................31 Interfejsy .......................................................................................31 Implementacje ...............................................................................32 Realistyczna ilustracja paradygmatu interfejsu i implementacji ...........33 Model paradygmatu interfejs – implementacja ..................................33 Dziedziczenie ......................................................................................34 Nadklasy i podklasy .......................................................................35 Abstrakcja .....................................................................................36 Zwi(cid:241)zek typu „jest” ........................................................................37 Polimorfizm .........................................................................................38 Kompozycja ........................................................................................41 Abstrakcja .....................................................................................41 Zwi(cid:241)zek typu „ma” .........................................................................41 Podsumowanie ....................................................................................41 Poleć książkęKup książkę 6 My(cid:264)lenie obiektowe w programowaniu Rozdzia(cid:228) 2 My(cid:264)lenie w kategoriach obiektowych .......................................43 Ró(cid:276)nica mi(cid:246)dzy interfejsem a implementacj(cid:241) ......................................... 44 Interfejs ........................................................................................ 46 Implementacja ............................................................................... 46 Przyk(cid:228)ad implementacji i interfejsu ................................................... 47 Zastosowanie my(cid:264)lenia abstrakcyjnego w projektowaniu interfejsów ........ 51 Minimalizowanie interfejsu ................................................................... 52 Okre(cid:264)lanie grupy docelowej ............................................................. 53 Zachowania obiektu ....................................................................... 54 Ograniczenia (cid:264)rodowiska ................................................................ 54 Identyfikowanie publicznych interfejsów ........................................... 54 Identyfikowanie implementacji ......................................................... 55 Podsumowanie ................................................................................... 56 (cid:273)ród(cid:228)a ................................................................................................ 56 Rozdzia(cid:228) 3 Inne poj(cid:246)cia z zakresu obiektowo(cid:264)ci .........................................57 Konstruktory ....................................................................................... 57 Kiedy wywo(cid:228)ywany jest konstruktor .................................................. 58 Zawarto(cid:264)(cid:232) konstruktora .................................................................. 58 Konstruktor domy(cid:264)lny ..................................................................... 58 Zastosowanie wielu konstruktorów .................................................. 59 Projektowanie konstruktorów .......................................................... 63 Obs(cid:228)uga b(cid:228)(cid:246)dów .................................................................................. 63 Ignorowanie problemu .................................................................... 64 Szukanie b(cid:228)(cid:246)dów i ko(cid:254)czenie dzia(cid:228)ania programu .............................. 64 Szukanie b(cid:228)(cid:246)dów i próba ich naprawienia ......................................... 64 Zg(cid:228)aszanie wyj(cid:241)tków ....................................................................... 65 Poj(cid:246)cie zakresu ................................................................................... 67 Atrybuty lokalne ............................................................................. 67 Atrybuty obiektowe ......................................................................... 68 Atrybuty klasowe ............................................................................ 70 Przeci(cid:241)(cid:276)anie operatorów ...................................................................... 71 Wielokrotne dziedziczenie .................................................................... 72 Operacje obiektów ............................................................................... 73 Podsumowanie ................................................................................... 74 (cid:273)ród(cid:228)a ................................................................................................ 74 Rozdzia(cid:228) 4 Anatomia klasy ........................................................................75 Nazwa klasy ........................................................................................ 75 Komentarze ........................................................................................ 77 Atrybuty .............................................................................................. 77 Konstruktory ....................................................................................... 78 Metody dost(cid:246)powe .............................................................................. 80 Metody interfejsu publicznego .............................................................. 83 Prywatne metody implementacyjne ....................................................... 83 Podsumowanie ................................................................................... 84 (cid:273)ród(cid:228)a ................................................................................................ 84 Poleć książkęKup książkę Spis tre(cid:264)ci 7 Rozdzia(cid:228) 5 Wytyczne dotycz(cid:241)ce projektowania klas ...................................85 Modelowanie systemów (cid:264)wiata rzeczywistego ........................................85 Identyfikowanie interfejsów publicznych .................................................86 Minimalizacja interfejsu publicznego ................................................86 Ukrywanie implementacji ................................................................87 Projektowanie niezawodnych konstruktorów i destruktorów .....................88 Projektowanie mechanizmu obs(cid:228)ugi b(cid:228)(cid:246)dów w klasie ...............................89 Pisanie dokumentacji i stosowanie komentarzy ................................89 Tworzenie obiektów nadaj(cid:241)cych si(cid:246) do kooperacji .............................90 Wielokrotne u(cid:276)ycie kodu .......................................................................90 Rozszerzalno(cid:264)(cid:232) ...................................................................................91 Tworzenie opisowych nazw ..............................................................91 Wyodr(cid:246)bnianie nieprzeno(cid:264)nego kodu ...............................................92 Umo(cid:276)liwianie kopiowania i porównywania obiektów ...........................92 Ograniczanie zakresu .....................................................................93 Konserwacja kodu ...............................................................................94 Iteracja ..........................................................................................94 Testowanie interfejsu .....................................................................95 Wykorzystanie trwa(cid:228)o(cid:264)ci obiektów .........................................................96 Serializacja i szeregowanie obiektów ...............................................97 Podsumowanie ....................................................................................98 (cid:273)ród(cid:228)a ................................................................................................98 Rozdzia(cid:228) 6 Projektowanie z wykorzystaniem obiektów ...............................99 Wytyczne dotycz(cid:241)ce projektowania ........................................................99 Wykonanie odpowiedniej analizy ....................................................103 Okre(cid:264)lanie zakresu planowanych prac ............................................103 Gromadzenie wymaga(cid:254) .................................................................103 Tworzenie prototypu systemu ........................................................104 Identyfikowanie klas .....................................................................104 Definiowanie wymaga(cid:254) wobec ka(cid:276)dej z klas ....................................104 Okre(cid:264)lenie warunków wspó(cid:228)pracy mi(cid:246)dzy klasami ...........................104 Tworzenie modelu klas opisuj(cid:241)cego system ...................................104 Tworzenie prototypu interfejsu u(cid:276)ytkownika za pomoc(cid:241) kodu ............105 Obiekty opakowuj(cid:241)ce .........................................................................105 Kod strukturalny ...........................................................................106 Opakowywanie kodu strukturalnego ...............................................107 Opakowywanie nieprzeno(cid:264)nego kodu .............................................108 Opakowywanie istniej(cid:241)cych klas ....................................................109 Podsumowanie ..................................................................................110 (cid:273)ród(cid:228)a ..............................................................................................110 Rozdzia(cid:228) 7 Dziedziczenie i kompozycja ....................................................111 Wielokrotne wykorzystywanie obiektów ................................................111 Dziedziczenie ....................................................................................112 Generalizacja i specjalizacja ..........................................................115 Decyzje projektowe .......................................................................116 Poleć książkęKup książkę 8 My(cid:264)lenie obiektowe w programowaniu Kompozycja ...................................................................................... 118 Reprezentowanie kompozycji na diagramach UML ........................... 118 Czemu hermetyzacja jest podstaw(cid:241) technologii obiektowej ................... 120 Jak dziedziczenie os(cid:228)abia hermetyzacj(cid:246) .......................................... 121 Szczegó(cid:228)owy przyk(cid:228)ad wykorzystania polimorfizmu ........................... 123 Odpowiedzialno(cid:264)(cid:232) obiektów .......................................................... 123 Klasy abstrakcyjne, metody wirtualne i protoko(cid:228)y ............................ 126 Podsumowanie ................................................................................. 127 (cid:273)ród(cid:228)a .............................................................................................. 128 Rozdzia(cid:228) 8 Wielokrotne wykorzystanie kodu — interfejsy i klasy abstrakcyjne ............................................129 Wielokrotne wykorzystanie kodu ......................................................... 129 Infrastruktura programistyczna ........................................................... 130 Co to jest kontrakt ............................................................................ 132 Klasy abstrakcyjne ....................................................................... 133 Interfejsy ..................................................................................... 135 Wnioski ....................................................................................... 137 Dowód kompilatora ...................................................................... 139 Zawieranie kontraktu .................................................................... 140 Punkty dost(cid:246)powe do systemu ...................................................... 142 Przyk(cid:228)ad biznesu elektronicznego ........................................................ 142 Biznes elektroniczny ..................................................................... 142 Podej(cid:264)cie niezak(cid:228)adaj(cid:241)ce wielokrotnego wykorzystania kodu ............ 143 Rozwi(cid:241)zanie dla aplikacji biznesu elektronicznego ........................... 145 Model obiektowy UML .................................................................. 145 Podsumowanie ................................................................................. 148 (cid:273)ród(cid:228)a .............................................................................................. 148 Rozdzia(cid:228) 9 Tworzenie obiektów i projektowanie obiektowe .......................149 Relacje kompozycji ............................................................................ 149 Podzia(cid:228) procesu budowy na etapy ....................................................... 151 Rodzaje kompozycji ........................................................................... 153 Agregacja .................................................................................... 153 Asocjacja .................................................................................... 153 (cid:227)(cid:241)czne wykorzystanie asocjacji i agregacji ...................................... 155 Unikanie zale(cid:276)no(cid:264)ci ........................................................................... 155 Liczno(cid:264)(cid:232) ........................................................................................... 156 Kilka asocjacji ............................................................................. 158 Asocjacje opcjonalne .................................................................... 159 Praktyczny przyk(cid:228)ad ............................................................................ 160 Podsumowanie ................................................................................. 161 (cid:273)ród(cid:228)a .............................................................................................. 161 Poleć książkęKup książkę Spis tre(cid:264)ci 9 Rozdzia(cid:228) 10 Wzorce projektowe ................................................................163 Historia wzorców projektowych ...........................................................164 Wzorzec MVC j(cid:246)zyka Smalltalk ............................................................165 Rodzaje wzorców projektowych ...........................................................166 Wzorce konstrukcyjne ...................................................................167 Wzorzec Metoda Fabryczna ...........................................................168 Wzorce strukturalne .....................................................................170 Wzorce czynno(cid:264)ciowe ...................................................................172 Antywzorce ........................................................................................174 Podsumowanie ..................................................................................175 (cid:273)ród(cid:228)a ..............................................................................................175 Rozdzia(cid:228) 11 Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami ......177 Kompozycja a dziedziczenie i wstrzykiwanie zale(cid:276)no(cid:264)ci .........................179 1. Dziedziczenie ...........................................................................179 2. Kompozycja .............................................................................181 Wstrzykiwanie zale(cid:276)no(cid:264)ci ...................................................................183 Wstrzykiwanie przez konstruktor ....................................................185 Wstrzykiwanie za pomoc(cid:241) metody ustawiaj(cid:241)cej ...............................185 Podsumowanie ..................................................................................186 (cid:273)ród(cid:228)a ..............................................................................................186 Rozdzia(cid:228) 12 Zasady SOLID projektowania obiektowego .............................187 Zasady SOLID projektowania obiektowego ...........................................188 1. Zasada jednej odpowiedzialno(cid:264)ci — SRP ...................................188 2. Zasada „otwarty/zamkni(cid:246)ty” — OCP .........................................191 3. Zasada podstawiania Liskov — LSP ..........................................193 4. Zasada segregacji interfejsów — IPS .........................................195 5. Zasada odwrócenia zale(cid:276)no(cid:264)ci — DIP ........................................196 Podsumowanie ..................................................................................201 (cid:273)ród(cid:228)a ..............................................................................................202 Skorowidz .............................................................................243 Poleć książkęKup książkę 10 My(cid:264)lenie obiektowe w programowaniu Poleć książkęKup książkę 11 Jak uniknąć zależności i silnych powiązań między klasami ak napisałem w rozdziale 1. zawierającym wprowadzenie do pojęć obiektowości, programowanie obiektowe tradycyjnie wyróżnia zastosowanie takich technik jak J hermetyzacja, dziedziczenie i polimorfizm. Aby język programowania teoretycznie można było nazwać obiektowym, musi spełniać warunki tych trzech technik, chociaż lubię jeszcze do nich dodawać kompozycję, którą także opisałem w rozdziale 1. W związku z tym podstawowy zestaw pojęć, jaki przedstawiam na zajęciach z programowania obiektowego, przedstawia się następująco: (cid:132) Hermetyzacja (cid:132) Dziedziczenie (cid:132) Polimorfizm (cid:132) Kompozycja Wskazówka Do listy tej mo(cid:276)na by jeszcze doda(cid:232) interfejsy, ale uwa(cid:276)am je za specjalny rodzaj dziedziczenia. Dziś ze względu na toczącą się w środowisku programistów dyskusję na temat poprawnego posługiwania się dziedziczeniem obecność kompozycji na tej liście wydaje się jeszcze ważniejsza. Wątpliwości wokół dziedziczenia nie są żadną nowością, ale w ostatnich latach debata na jego temat nabrała rumieńców. Wielu programistów, z którymi rozmawiam, opowiada się za kompozycją zamiast dziedziczenia. Niektórzy nawet starają się go w ogóle unikać albo przynajmniej ograniczyć je do jednego poziomu hierarchii. Dyskusje dotyczące sposobów posługiwania się dziedziczeniem krążą wokół tematu powiązań. Argumenty za nim to przede wszystkim możliwość wielokrotnego wykorzystania kodu, rozszerzalność i polimorfizm. Należy też jednak pogodzić się z możliwością powstania zależności między klasami, czyli powiązaniem klas. Zależności te sprawiają problemy zarówno podczas konserwacji, jak i testowania kodu. Poleć książkęKup książkę 178 Rozdzia(cid:228) 11. Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami W rozdziale 7. „Dziedziczenie i kompozycja” opisałem, jak przez dziedziczenie może dojść do osłabienia hermetyzacji, co wydaje się bez sensu, ponieważ są to dwa podstawowe pojęcia. A jednak na tym polega zabawa i zmusza nas to do dokładnego zastanowienia się nad tym, w jaki sposób posługiwać się dziedziczeniem. Ostrze(cid:276)enie Podkre(cid:264)l(cid:246), (cid:276)e nie jestem przeciwnikiem pos(cid:228)ugiwania si(cid:246) dziedziczeniem. W rozdziale tym opisuj(cid:246) metody unikania zale(cid:276)no(cid:264)ci i (cid:264)cis(cid:228)ych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami, a prawid(cid:228)owe pos(cid:228)ugiwanie si(cid:246) dziedziczeniem stanowi wa(cid:276)ny element tej uk(cid:228)adanki. Powyższe rozważania nieuchronnie prowadzą do następującego pytania: jeśli nie dziedziczenie, to co? Odpowiedź, że kompozycja, nikogo nie zdziwi, ponieważ od początku tej książki podkreślam, że są tylko dwa sposoby na wielokrotne wykorzystanie klas — dziedziczenie i kompozycja właśnie. Programista może utworzyć klasę potomną za pomocą dziedziczenia lub może umieścić jedną klasę w innej klasie, korzystając z technik kompozycji. Jeśli zgodnie z zaleceniami niektórych programistów dziedziczenia należy unikać, to po co w ogóle marnować czas na naukę posługiwania się nim? Odpowiedź jest prosta: technika ta jest wykorzystywana w wielu programach. Programiści bardzo szybko się przekonują, że ogromna większość istniejącego kodu wymaga poprawiania. Aby naprawiać, ulepszać i doskonalić kod napisany przy użyciu technik dziedziczenia, należy te techniki rozumieć. Czasami nawet pisze się własny kod z ich wykorzystaniem. Krótko mówiąc, programista musi znać wszystkie podstawowe techniki oraz powinien dysponować pełnym wachlarzem narzędzi programistycznych. To jednak zmusza do ciągłego poznawania nowych narzędzi i zmiany sposobu myślenia o tych, które już znamy. Jeszcze raz podkreślę, że nie chodzi mi o jakiekolwiek osądzanie pod względem wartości. Nie twierdzę, że dziedziczenie sprawia problemy i że należy go unikać. Chcę tylko zaznaczyć, jak ważne jest dokładne zrozumienie dziedziczenia, zapoznanie się z innymi metodami projektowania oraz wybranie najbardziej odpowiedniej dla siebie. Dlatego też przykłady prezentowane w tym rozdziale niekoniecznie przedstawiają optymalny sposób zaprojektowania klas. To tylko ćwiczenia, które mają zachęcić do przemyślenia kwestii związanych z wyborem między dziedziczeniem i kompozycją. Pamiętajmy, że tak ewoluują wszystkie technologie — zachowują to, co w nich dobre, i doskonalą to, co ma wady. Ponadto kompozycja także nie jest wolna od problemów dotyczących powiązań między klasami. W rozdziale 7. opisałem różne typy kompozycji: asocjację i agregację. Agregacja to obiekty umieszczone w innych obiektach (utworzonych za pomocą słowa kluczowego new), natomiast asocjacja to obiekty przekazywane do innych obiektów za pośrednictwem listy parametrów. Skoro agregacje są osadzone w obiektach, to znaczy, że są z nimi ściśle powiązane, a tego przecież chcemy uniknąć. Dlatego, choć dziedziczenie może mieć opinię techniki sprzyjającej silnemu wiązaniu klas, kompozycja (przy użyciu agregacji) także może sprawiać takie same problemy. Wrócimy do przykładu ze sprzętem stereo z rozdziału 9. „Tworzenie obiektów i projektowanie obiektowe” i na jego podstawie połączymy wszystkie te koncepcje w jedną całość. Tworzenie zestawu stereo przy użyciu agregacji można porównać do tworzenia szafy grającej, która jest sprzętem zawierającym wszystkie komponenty wewnątrz jednej obudowy. Rozwiązanie takie w wielu sytuacjach jest bardzo wygodne. Szafę można podnieść, przesunąć Poleć książkęKup książkę Kompozycja a dziedziczenie i wstrzykiwanie zale(cid:276)no(cid:264)ci 179 i nie wymaga ona specjalnych umiejętności przy składaniu. Z drugiej strony taka konstrukcja może też nastręczać liczne problemy. Jeśli popsuje się któryś z komponentów, na przykład odtwarzacz MP3, to do naprawy trzeba oddać całe urządzenie. Co gorsza, może zdarzyć się tak, że jakaś awaria, na przykład zasilania, zniszczy całą szafę grającą za jednym zamachem. Wiele z problemów wynikających z użycia agregacji można zlikwidować, posługując się asocjacją. Wyobraź sobie, że system stereo jest zestawem asocjacji połączonych przewodami (albo bezprzewodowo). W takiej konstrukcji występuje centralny obiekt zwany odbiornikiem, z którym łączą się inne obiekty, takie jak głośniki, odtwarzacze CD czy nawet konsole do miksowania i magnetofony. Można nawet pokusić się o stwierdzenie, że to rozwiązanie niezależne od dostawcy, ponieważ każdy komponent możemy kupić osobno, co jest wielką zaletą tego rozwiązania. Jeśli w takim zestawie popsuje się odtwarzacz CD, wystarczy go odłączyć i oddać do naprawy (jednocześnie nadal korzystając z pozostałych części) lub wymienić na nowy. Taka jest zaleta asocjacji i ograniczenia do minimum powiązań między klasami. Wskazówka Jak napisa(cid:228)em w rozdziale 9., cho(cid:232) generalnie (cid:264)cis(cid:228)e powi(cid:241)zania mi(cid:246)dzy klasami s(cid:241) niemile widziane, czasami mo(cid:276)na zaakceptowa(cid:232) t(cid:246) niedogodno(cid:264)(cid:232). Jednym z przyk(cid:228)adów takiej sytuacji jest opisana wcze(cid:264)niej szafa graj(cid:241)ca. Mimo (cid:264)cis(cid:228)ego powi(cid:241)zania jej komponentów taka konstrukcja ma pewne zalety. Wiemy już, jakie problemy sprawiają ścisłe powiązania komponentów zarówno w przypadku dziedziczenia, jak i kompozycji, więc teraz przyjrzymy się paru przykładom ściśle powiązanych projektów utworzonych przy użyciu tych technik. Na wzór zajęć, które prowadzę, będziemy stopniowo przebudowywać te przykłady, aż dojdziemy do techniki zwanej wstrzykiwaniem zależności, która pozwoli nam ograniczyć problemy związane z powiązaniem komponentów. Kompozycja a dziedziczenie i wstrzykiwanie zale(cid:276)no(cid:264)ci Na początek zastanowimy się, jak przeprojektować model dziedziczenia (typowy dla przykładów często używanych w tej książce) przy użyciu kompozycji. Drugi przykład pokazuje sposób zmiany projektu z wykorzystaniem kompozycji, choć przy użyciu agregacji, która nie zawsze jest optymalnym rozwiązaniem. Trzeci przykład pokazuje, jak uniknąć agregacji i zamiast nich zaprojektować system przy użyciu asocjacji — przedstawia zatem koncepcję wstrzykiwania zależności. 1. Dziedziczenie Niezależnie od tego, czy uznajesz wyższość kompozycji nad dziedziczeniem, na początek przeanalizujemy prosty przykład dziedziczenia oraz sprawdzimy, jak zaimplementować go przy użyciu kompozycji, po drodze przypominając sobie przykład dotyczący ssaków, który towarzyszy nam od początku książki. Tym razem wprowadzimy nietoperza, czyli latającego ssaka — rysunek 11.1. Poleć książkęKup książkę 180 Rozdzia(cid:228) 11. Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami Rysunek 11.1. Tworzenie obiektów ssaków przy u(cid:276)yciu dziedziczenia W tym konkretnym przykładzie dziedziczenie wydaje się oczywistym wyborem. Utworzenie klasy Dog, która dziedziczy po klasie Mammal, to doskonały pomysł, prawda? Spójrz na poniższy kod, w którym właśnie w taki sposób wykorzystano dziedziczenie: class Mammal { public void eat () {System.out.println( Jem );}; } class Bat extends Mammal { public void fly () {System.out.println( Latam );}; } class Dog extends Mammal { public void walk () {System.out.println( Chodz(cid:218) );}; } public class TestMammal { public static void main(String args[]) { System.out.println( Kompozycja ponad dziedziczeniem );; System.out.println( \nDog ); Dog fido = new Dog(); fido.eat(); fido.walk(); System.out.println( \nBat ); Bat brown = new Bat(); brown.eat(); brown.fly(); } } W tym projekcie klasa Mammal ma jedno zachowanie — eat() — wynikające z założenia, że wszystkie ssaki muszą jeść. Jednak już po dodaniu dwóch podklas, Bat i Dog, zaczynamy dostrzegać problem. Choć psy potrafią chodzić, nie wszystkie ssaki mają tę umiejętność. Poleć książkęKup książkę Kompozycja a dziedziczenie i wstrzykiwanie zale(cid:276)no(cid:264)ci 181 Z drugiej strony nietoperze latają, ale to też jest umiejętność tylko wybranych ssaków. Gdzie w takim razie umieścić metody odpowiadające tym zdolnościom? Podobnie jak w przypadku wcześniejszego przykładu z pingwinami, fakt, że nie wszystkie ptaki potrafią latać, sprawia, że w hierarchii dziedziczenia trudno jest znaleźć odpowiednie miejsce do umieszczenia niektórych metod. Podział klasy Mammal na klasy FlyingMammals i WalkingMammals jest nieeleganckim rozwiązaniem, ponieważ to tylko wierzchołek góry lodowej. Niektóre ssaki potrafią pływać, a część z nich nawet składa jaja. Poza tym poszczególne gatunki ssaków wyróżniają się przeróżnymi wyjątkowymi zdolnościami i tworzenie osobnej klasy dla wszystkich tych zachowań byłoby wyjątkowo niepraktyczne. Dlatego w tym przypadku zamiast posługiwać się relację typu „jest”, lepiej postawić na relację „ma”. 2. Kompozycja W tej strategii zamiast umieszczać zachowania w samych klasach, dla każdego zachowania tworzymy osobną klasę. W ten sposób zamiast umieszczać zachowania w hierarchii dziedziczenia, możemy utworzyć klasę dla każdego zachowania, po czym możemy tworzyć poszczególne ssaki przy użyciu odpowiednich dla nich umiejętności (poprzez agregację). W związku z tym tworzymy klasy Walkable i Flyable, jak widać na rysunku 11.2. Rysunek 11.2. Tworzenie ssaków za pomoc(cid:241) kompozycji Spójrz na poniższy kod. Nadal mamy klasę Mammal z metodą eat() oraz nadal mamy klasy Dog i Bat. Główna różnica projektowa dotyczy tego, że klasy Dog i Bat uzyskują swoje zachowania przy użyciu kompozycji, poprzez agregację. Ostrze(cid:276)enie Pami(cid:246)taj, (cid:276)e w poprzednim akapicie wyst(cid:241)pi(cid:228)o poj(cid:246)cie agregacji. Ten przyk(cid:228)ad ilustruje sposób u(cid:276)ycia kompozycji zamiast dziedziczenia, ale w postaci agregacji, która tak(cid:276)e jest obci(cid:241)(cid:276)ona silnymi powi(cid:241)zaniami. Dlatego nale(cid:276)y to traktowa(cid:232) jako etap po(cid:264)redni na drodze do nast(cid:246)pnego przyk(cid:228)adu z wykorzystaniem interfejsów. Poleć książkęKup książkę 182 Rozdzia(cid:228) 11. Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami class Mammal { public void eat () {System.out.println( Jem );}; } class Walkable { public void walk () {System.out.println( Chodz(cid:218) );}; } class Flyable { public void fly () {System.out.println( Latam );}; } class Dog { Mammal dog = new Mammal(); Walkable walker = new Walkable(); } class Bat { Mammal bat = new Mammal(); Flyable flyer = new Flyable(); } public class TestMammal { public static void main(String args[]) { System.out.println( Kompozycja ponad dziedziczeniem );; System.out.println( \nDog );; Dog fido = new Dog(); fido.dog.eat(); fido.walker.walk(); System.out.println( \nBat );; Bat brown = new Bat(); brown.bat.eat(); brown.flyer.fly(); } } Uwaga Celem tego przyk(cid:228)adu jest pokazanie, jak zast(cid:241)pi(cid:232) dziedziczenie kompozycj(cid:241). To nie znaczy, (cid:276)e z dziedziczenia nale(cid:276)y ca(cid:228)kowicie zrezygnowa(cid:232). Je(cid:264)li stwierdzisz, (cid:276)e absolutnie wszystkie ssaki musz(cid:241) je(cid:264)(cid:232), to metod(cid:246) eat() mo(cid:276)esz umie(cid:264)ci(cid:232) w klasie Mammal, po której b(cid:246)d(cid:241) dziedziczy(cid:232) klasy Dog i Bat. To typowa decyzja projektanta. W tym przypadku najistotniejsze jest chyba to, o czym pisałem już wcześniej, że dziedziczenie narusza hermetyzację. Łatwo to zrozumieć, ponieważ zmiana w klasie Mammal wymagałaby ponownej kompilacji (i zapewne nawet nowego wdrożenia) wszystkich jej podklas. To oznacza, że klasy są silnie powiązane, co stoi w sprzeczności z naszym celem ograniczenia do minimum powiązań między klasami. Gdybyśmy w naszym przykładzie kompozycji chcieli dodać klasę Whale (wieloryb), to żadna z poprzednich klas nie wymagałaby przepisania. Wystarczyłoby dodać klasy Swimmable i Whale. Następnie klasy Swimmable moglibyśmy też użyć do budowy na przykład klasy Dolphin. class Swimmable { public void fly () {System.out.println( P(cid:239)ywam );}; } class Whale { Mammal whale = new Mammal(); Walkable swimmer = new Swimmable (); } Poleć książkęKup książkę Funkcjonalność tę można dodać do klasy głównej bez wprowadzania jakichkolwiek zmian Wstrzykiwanie zale(cid:276)no(cid:264)ci 183 we wcześniejszych klasach. System.out.println( \nWhale ); Whale shamu = new Whale(); shamu.whale.eat(); shamu.swimmer.swim(); Jedną z podstawowych zasad jest korzystanie z dziedziczenia tylko w przypadkach prawdziwego polimorfizmu, a więc technika ta może świetnie sprawdzić się dla kół i prostokątów dziedziczących po klasie Shape. Z drugiej strony wybór dziedziczenia dla takich zachowań jak chodzenie i latanie może być nie najlepszy, ponieważ ich przesłanianie może sprawiać trudności. Gdybyśmy na przykład w klasie Dog mieli przesłonić metodę fly(), to jedynym sensownym wyjściem byłoby, aby nic ona nie robiła. Podobnie jak we wcześniejszym przykładzie z pingwinem, nie chcielibyśmy przecież, aby nasz pies skoczył z urwiska, po czym wykonał dostępną metodę fly() tylko po to, by ku swemu przerażeniu stwierdzić, że nic ona nie robi. Choć w tej implementacji wykorzystaliśmy kompozycję, projekt ten ma jedną poważną wadę. Obiekty są ściśle powiązane, ponieważ użycie słowa kluczowego new jest tu oczywiste. class Whale { Mammal whale = new Mammal(); Walkable swimmer = new Swimmable (); } Aby naprawdę doprowadzić do rozdzielenia klas, wprowadzimy pojęcie wstrzykiwania zależności. Krótko mówiąc, zamiast tworzyć obiekty w innych obiektach, będziemy wstrzykiwać obiekty z zewnątrz za pośrednictwem list parametrów. Opis dotyczy wyłącznie koncepcji wstrzykiwania zależności. Wstrzykiwanie zale(cid:276)no(cid:264)ci W poprzednim przykładzie posłużyliśmy się kompozycją (z agregacją), aby nadać psu (Dog) umiejętność chodzenia (Walkable). Klasa Dog dosłownie tworzyła nowy obiekt Walkable w swoim wnętrzu, jak ilustruje poniższy fragment kodu: class Dog { Walkable walker = new Walkable(); } Choć to wprawdzie działa, taka klasa jest ściśle powiązana z inną klasą. Aby pozbyć się tego powiązania z poprzedniego przykładu, posłużymy się wspominaną już wcześniej koncepcją wstrzykiwania zależności. Technice tej zazwyczaj towarzyszy pojęcie odwrócenia kontroli (ang. inversion of control — IOC). Polega ono na tym, że przerzucamy zadanie utworzenia obiektu na kogoś innego, po czym każemy sobie ten obiekt przekazać. Właśnie taki sposób działania zaimplementujemy teraz w tym przykładzie. Ponieważ nie wszystkie ssaki chodzą, latają lub pływają, proces likwidacji powiązań rozpoczniemy od utworzenia interfejsów reprezentujących umiejętności różnych gatunków ssaków. W przykładzie skupiam się na umiejętności chodzenia, którą będzie reprezentować interfejs IWalkable (rysunek 11.3). Poleć książkęKup książkę 184 Rozdzia(cid:228) 11. Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami Rysunek 11.3. Tworzenie obiektów ssaków przy u(cid:276)yciu interfejsów Kod źródłowy interfejsu IWalkable wygląda następująco: interface IWalkable { public void walk(); } Zawiera on tylko jedną metodę o nazwie walk(), której implementacja powinna się znaleźć w implementacji konkretnej klasy. class Dog extends Mammal implements IWalkable{ Walkable walker; public void setWalker (Walkable w) { this.walker=w; } public void walk () {System.out.println( Chodz(cid:218) );}; } Klasa Dog rozszerza klasę Mammal i implementuje interfejs IWalkable. Ponadto klasa Dog zawiera referencję i konstruktor umożliwiający wstrzykiwanie zależności. Walkable walker; public void setWalker (Walkable w) { this.walker=w; } Na tym w skrócie polega wstrzykiwanie zależności. Zachowanie Walkable nie zostało utworzone wewnątrz klasy Dog za pomocą słowa kluczowego new, tylko wstrzyknięto je przy użyciu listy parametrów. Oto kompletny przykład: class Mammal { public void eat () {System.out.println( Jem );}; } interface IWalkable { public void walk(); } Poleć książkęKup książkę Wstrzykiwanie zale(cid:276)no(cid:264)ci 185 class Dog extends Mammal implements IWalkable{ Walkable walker; public void setWalker (Walkable w) { this.walker=w; } public void walk () {System.out.println( Chodz(cid:218) );}; } public class TestMammal { public static void main(String args[]) { System.out.println( Kompozycja ponad dziedziczeniem ); System.out.println( \nDog ); Walkable walker = new Walkable(); Dog fido = new Dog(); fido.setWalker(walker); fido.eat(); fido.walker.walk(); } } W tym przykładzie wstrzyknięcie zostało zrealizowane za pomocą konstruktora, ale nie jest to jedyny sposób na zastosowanie tej techniki. Wstrzykiwanie przez konstruktor Jednym ze sposobów na wstrzyknięcie zachowania Walkable jest utworzenie konstruktora w klasie Dog, który będzie przyjmował argument z aplikacji głównej: class Dog { Walkable walker; public Dog (Walkable w) { this.walker=w; } } W tym przypadku aplikacja tworzy obiekt Walkable i wstawia go do Dog za pomocą konstruktora. Walkable walker = new Walkable(); Dog fido = new Dog(walker); Wstrzykiwanie za pomoc(cid:241) metody ustawiaj(cid:241)cej Choć konstruktor inicjalizuje atrybuty w chwili tworzenia obiektu, w czasie istnienia obiektu często występuje potrzeba zresetowania wartości. Do tego wykorzystuje się metody ustawiające, czyli settery. Zachowanie Walkable można wstawić do klasy Dog za pomocą metody ustawiającej o nazwie setWalker(): class Dog { Walkable walker; public void setWalker (Walkable w) { this.walker=w; } } Podobnie jak w przypadku techniki z wykorzystaniem konstruktora, aplikacja tworzy obiekt Walkable. Następnie obiekt ten jest wstawiany do klasy Dog za pomocą settera: Poleć książkęKup książkę 186 Rozdzia(cid:228) 11. Jak unikn(cid:241)(cid:232) zale(cid:276)no(cid:264)ci i silnych powi(cid:241)za(cid:254) mi(cid:246)dzy klasami Walkable walker = new Walkable(); Dog fido = new Dog(); fido.setWalker(walker); Podsumowanie Wstrzykiwanie zależności oddziela proces tworzenia obiektu klasy od jej zależności. To czynność bardziej przypominająca branie rzeczy z półki (od dostawcy) niż samodzielne ich tworzenie za każdym razem. Jest to kluczowy element dyskusji dotyczącej dziedziczenia i kompozycji, choć należy podkreślić, że to tylko dyskusja. W rozdziale tym moim celem nie było przedstawienie „optymalnego” sposobu projektowania klas, lecz zachęcenie Cię do przemyślenia kwestii związanych z podejmowaniem decyzji podczas wyboru między dziedziczeniem i kompozycją. W następnym rozdziale opisuję zasady SOLID projektowania obiektowego, które są powszechnie akceptowane i cenione w środowiskach programistów. (cid:273)ród(cid:228)a Robert C. Martin, Zwinne wytwarzanie oprogramowania. Najlepsze zasady, wzorce i praktyki, Helion, Gliwice 2015. Robert C. Martin, Czysty kod. Podręcznik dobrego programisty, Helion, Gliwice 2009. Poleć książkęKup książkę
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Myślenie obiektowe w programowaniu. Wydanie V
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: