Być może największą obietnicą użycia paradygmatu obiektowego jest ponowne użycie kodu. Niektórzy spierają się, że udało się to osiągnąć. Dlaczego został (nie) osiągnięty?
Czy kod jest ponownie wykorzystywany, ponieważ definiuje go OOP, czy projekty są bardziej produktywne?
Lub łatwiejszy w zarządzaniu? Lub łatwiejsze w utrzymaniu? A może z lepszą jakością?
Prawdopodobnie wszyscy zgadzamy się, że ponowne użycie kodu jest dobrą rzeczą, ale istnieje kilka sposobów na osiągnięcie tego celu. Pytanie dotyczy metody ponownego wykorzystania kodu oferowanej przez OOP. Czy to dobrze? Czy istnieją lepsze metody ponownego wykorzystania kodu niż orientacja obiektowa, podklasowanie, polimorfizm itp.? Jakie są lepsze sposoby? Dlaczego ?
Poinformuj nas o swoich doświadczeniach z ponownym użyciem OOP lub ponownym wykorzystaniu innych paradygmatów.
źródło
Odpowiedzi:
Ponowne użycie kodu jest całkiem dobrym pomysłem. Niezbyt dobry .
Mam perspektywę zaczerpniętą z około 30 lat inżynierii oprogramowania, która próbuje „ponownie wykorzystać”.
Zacząłem badać „ponowne użycie kodu” jako temat badawczy już w latach 80., po odkryciu, że ponownie wykorzystałem projekt jednego systemu operacyjnego, który zbudowałem na początku lat 70., dla innego systemu operacyjnego, który zbudowałem pod koniec lat 70.
Dobrą częścią ponownego wykorzystania kodu jest zdolność do ponownego wykorzystania istniejącego wcześniej, uczciwego boga kodu. Ale świat jest pełen kodu; jak znaleźć to, czego chcesz? Oto, co nazywam klątwą ponownego użycia :
Jestem Święty Mikołaj (ok Open Source) i mam worek 1 miliarda komponentów oprogramowania. Możesz mieć jeden z nich.
Powodzenia w wyborze.
Aby dobrze rozwiązać problem ponownego użycia:
Przez lata odkryto przede wszystkim, że aby kod mógł być ponownie użyty, musi być zaprojektowany w tym celu lub zawiera zbyt wiele domniemanych założeń. Biblioteki, które odniosły największe sukcesy, były w rzeczywistości dość małe. Prawdopodobnie biblioteki i frameworki są kodem „wielokrotnego użytku” i odnoszą ogromne sukcesy; Java i C # odnoszą sukcesy nie dlatego, że są całkiem niezłymi językami komputerowymi, ale raczej dlatego, że mają do dyspozycji ogromne, dobrze zaprojektowane, zaimplementowane i udokumentowane biblioteki. Ale ludzie nie patrzą na kod źródłowy w bibliotekach; po prostu wywołują dobrze udokumentowany interfejs API (zaprojektowany tak, aby był ogólnie użyteczny).
To, czego ponowne użycie kodu nie dokonało (OOP też), zapewnia poprawę wielkości naszych systemów kodowania.
Myślę, że kluczową wadą jest to, że jakiekolwiek ponowne użycie kodu jest zasadniczo ograniczone, ponieważ kod ma zbyt wiele założeń . Jeśli sprawisz, że kod będzie mały, zminimalizujesz założenia, ale wtedy koszt budowy od zera nie będzie bardzo duży, a zyski z ponownego użycia nie będą skuteczne. Jeśli sprawisz, że fragmenty kodu będą ogromne, będą one prawie bezużyteczne w nowym kontekście. Podobnie jak Guliwer, są przywiązani do plaży milionem małych sznurków i po prostu nie możesz sobie pozwolić na przecięcie ich wszystkich.
Powinniśmy pracować nad ponownym wykorzystaniem wiedzy do konstruowania kodu . Jeśli możemy to zrobić, możemy zastosować tę wiedzę do skonstruowania potrzebnego nam kodu, obsługując bieżący zestaw założeń.
Aby to zrobić, nadal potrzebna jest ta sama zdolność specyfikacji do charakteryzowania komponentów oprogramowania (wciąż musisz powiedzieć, co chcesz!). Ale następnie zastosujesz tę wiedzę „konstrukcyjną” do specyfikacji, aby wygenerować pożądany kod.
Jako społeczność nie jesteśmy jeszcze w tym zbyt dobrzy. Ale ludzie robią to cały czas; dlaczego nie możemy tego zautomatyzować? Istnieje wiele badań, co pokazuje, że można to zrobić w wielu okolicznościach.
Jednym z kluczowych urządzeń potrzebnych do tego są mechaniczne narzędzia do akceptowania „opisów komponentów” (są to tylko formalne dokumenty i można je analizować jak języki programowania) i stosować do nich transformacje programów .
Kompilatory już to robią: -} I są naprawdę dobre w klasie problemów, które rozwiązują.
Modele UML z generowaniem kodu to jedna próba tego. Niezbyt dobra próba; właściwie w większości modeli UML mówi się: „Mam dane, które wyglądają tak”. Trudno jest wygenerować prawdziwy program, jeśli pominięto funkcjonalność.
Próbuję zbudować praktyczne systemy transformacji programów, narzędzie o nazwie DMS . Byłem dość dobrze rozproszony, stosując transformacje programu nie tyle do abstrakcyjnych specyfikacji, aby wygenerować kod, ale raczej do starszego kodu, aby go wyczyścić. (Są to ten sam problem w streszczeniu!). (Budowa takich narzędzi zajmuje dużo czasu; robię to od 15 lat, a tymczasem musisz jeść).
Ale DMS ma dwie kluczowe właściwości, które opisałem powyżej: możliwość przetwarzania dowolnych specyfikacji formalnych oraz zdolność do przechwytywania „wiedzy na temat generowania kodu” jako transformacji i stosowania ich na żądanie. I, co niezwykłe, generujemy w niektórych szczególnych przypadkach jakiś dość interesujący kod ze specyfikacji; DMS jest w dużej mierze zbudowany przy użyciu samego siebie do generowania swojej implementacji. To osiągnęło dla nas przynajmniej część obietnicy ponownego wykorzystania (wiedzy): wyjątkowo znacznego wzrostu wydajności. Mam zespół około 7 osób technicznych; napisaliśmy prawdopodobnie 1-2 MSLOC „specyfikacji” dla DMS, ale mamy około 10MSLOC wygenerowanego kodu.
Podsumowanie: ponowne wykorzystanie wiedzy generacyjnej to zwycięstwo, a nie ponowne użycie kodu .
źródło
Mostly what has been discovered over the years is that for code to be reusable, it sort of has to be designed for that purpose, or it contains too many implicit assumptions.
Doszedłem do podobnego wniosku, ale nie mogłem wyrazić tego tak zwięźle.Ponowne użycie kodu jest osiągane w OOP, ale jest również osiągane w programowaniu funkcjonalnym. Za każdym razem, gdy pobierzesz blok kodu i sprawisz, że będzie można go wywołać przez resztę kodu, abyś mógł korzystać z tej funkcji w innym miejscu, jest ponowne użycie kodu.
Ten rodzaj ponownego użycia kodu sprawia, że kod jest łatwiejszy w zarządzaniu, ponieważ zmiana tego jednego bloku na żądanie zmienia wszystkie miejsca, które są nazywane. Powiedziałbym, że ten wynik również poprawił jakość i czytelność.
Nie jestem pewien, czy OOP jest po to, aby zapewnić ponowne użycie kodu. Patrzę na OOP jako sposób na interakcję z obiektami i abstrahowanie szczegółów struktury danych.
Z Wikpedia:
źródło
double sqrt (double x)
? Czyste funkcje są archetypem ponownego użycia.double sqrt(double x)
,float sqrt(float x)
,int sqrt(int x)
można zdefiniować wiele z nich, podczas gdy z ogólnym języku programowania trzebaNumber sqrt(Number x)
i można z nim zrobić.Tak i nie
Ponowne użycie kodu jest terminem uniwersalnym dla wielu różnych działań.
źródło
Chciałbym zamieścić długą odpowiedź, ale dlaczego? Udi Dahan wyjaśnia to znacznie lepiej niż potrafię.
http://www.udidahan.com/2009/06/07/the-fallacy-of-reuse/
Oto początek posta:
źródło
Zgadzam się z Chrisem, programowanie funkcjonalne jest dobrym sposobem na ponowne użycie kodu.
Wiele programów ma powtarzające się struktury kodu. W tym celu w świecie OOP stosowane są niektóre wzorce projektowe , ale można to osiągnąć przez funkcje rekurencyjne i dopasowanie wzorców w funkcjonalnych językach programowania. Więcej informacji na ten temat znajduje się w pierwszym rozdziale Programowania funkcjonalnego w rzeczywistym świecie .
Myślę, że głębokie dziedzictwo w OOP może w wielu przypadkach wprowadzać w błąd. Masz klasę, a wiele ściśle powiązanych metod jest zaimplementowanych w różnych plikach. Jak powiedział Joe Armstrong o OOP:
Funkcje wysokiego rzędu są również bardzo przydatne, jeśli chodzi o ponowne użycie kodu, np.
map
Ifoldr
jest to podstawa MapReduce firmy Google .Asynchroniczne przekazywanie wiadomości jest również dobrym sposobem na zorganizowanie złożonego oprogramowania, a niektórzy informatycy twierdzą, że założono, że obiekty komunikują się ze sobą asynchronicznie jak w Tell, nie pytaj o zasadę OOP. Zobacz więcej na ten temat w Programowaniu obiektowym: zła ścieżka? gdzie cytowany jest Joe Armstrong :
Asynchroniczne przekazywanie komunikatów jak w systemach sterowanych zdarzeniami oraz w Erlang jest również bardzo dobrym sposobem na odsprzęganie systemów, a luźne sprzężenie jest ważne w złożonych systemach. Przy dostatecznie oddzielonym systemie możesz ewoluować system podczas pracy, być może w różnych węzłach. Unibet przygotował świetną prezentację na ten temat: Architektura oparta na zdarzeniach domenowych
Myślę jednak, że większość ponownego użycia kodu odbywa się przy użyciu bibliotek i frameworków.
źródło
Skromny potok unix zrobił więcej w zakresie ponownego wykorzystania kodu niż wszystko inne, co pojawiło się i zniknęło. Przedmioty okazały się być intuicyjnym sposobem strukturyzacji kodu, kiedy się pojawiały, a później ludzie zaczęli przyczepiać się do wszystkiego i wszystkiego na nim. Ogólnie rzecz biorąc, obiekty służą do enkapsulacji, a nie do ponownego użycia kodu, ponowne użycie kodu wymaga czegoś więcej, a hierarchia dziedziczenia klas jest słabym substytutem tego, czym tak naprawdę powinien być mechanizm ponownego wykorzystania kodu.
źródło
OOP nie jest niczym specjalnym; możesz tworzyć kod wielokrotnego użytku z lub bez OOP. Czyste funkcje są szczególnie wielokrotnego użytku : na przykład
java.lang.math.sqrt(double)
przyjmuje liczbę i podaje liczbę. Bez OOP, ale zdecydowanie bardziej wielokrotnego użytku niż większość dostępnych kodów.źródło
Z punktu widzenia programowania funkcjonalnego OOP dotyczy głównie zarządzania stanem.
W programowaniu funkcjonalnym możesz łatwo mieć setki przydatnych funkcji dla list: http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-List.html .
Czy masz setki metod w klasie List? Metody publiczne są uważane za interfejs do stanu wewnętrznego, który ma być niewielki.
Niestety, zamiast (ponownego) używania wielu małych funkcji, niektórzy ludzie powielały funkcjonalność. Dla mnie to dlatego, że OOP nie zachęca do ponownego użycia kodu tak bardzo, jak programowanie funkcjonalne.
źródło
Dla mnie tak, ale nie przez cały czas, i można było to zrobić na inne sposoby.
Przez większość czasu, tworząc abstrakcyjną klasę bazową i tworząc konkretne implementacje tej klasy.
Wiele frameworków korzysta z dziedziczenia w celu ponownego wykorzystania kodu (Delphi, Java, .Net to tylko niektóre, które przychodzą na myśl natychmiast).
Nie oznacza to, że wiele bibliotek narzędziowych i fragmentów kodu również nie wykonało zadania, ale w dobrze zaprojektowanej hierarchii obiektów jest coś przyjemnego.
źródło
Z mojego doświadczenia odnoszę większy sukces w wykorzystywaniu kodu „wielokrotnego użytku” za pomocą ogólnych narzędzi programistycznych (takich jak szablony C ++) niż przy użyciu zasad OOP, takich jak hierarchie dziedziczenia.
źródło
OOP jest zbyt otwarty, aby można go było ponownie wykorzystać.
Jest zbyt wiele sposobów na ponowne użycie. Każda klasa publiczna pyta: „stwórz ze mnie nową instancję!” , każda metoda publiczna mówi: „zadzwoń do mnie!” , każda chroniona metoda daje: „zastąp mnie!” - i wszystkie te sposoby ponownego użycia są różne , mają różne parametry, pojawiają się w innym kontekście, wszystkie mają swoje różne zasady, jak je wywoływać / rozszerzać / zastępować.
Interfejs API jest lepszy, jest to ścisły podzbiór punktów OOP (lub non-oop), ale w rzeczywistości interfejsy API są nadmiernie rozbudowane i stale rosną, wciąż istnieje zbyt wiele punktów połączenia. Ponadto dobry interfejs API może ułatwić życie, jest to najlepszy sposób na zapewnienie interfejsu dla OOP.
Paradigm Datadlow zapewnia ścisły interfejs dla komponentów, mają porty następujących typów:
W zależności od domeny istnieją pewne typy pakietów, więc klienci i producenci mogą być podłączeni, ponieważ mają te same (lub zgodne) porty. Najpiękniejsza część, którą można zrobić wizualnie, ponieważ nie ma żadnych parametrów ani innych poprawek na połączeniach, tak naprawdę po prostu łączą one konsumenta i producenta.
Byłem trochę niejasne, można spojrzeć na „przepływu danych” tag na StackOverflow lub Wikipedia „datafow programowania” lub Wikipedia „programowanie oparte przepływowym” .
(Napisałem również system przepływu danych w C ++. Więc OOP i DF nie są wrogami, DF to sposób organizacji na wyższym poziomie).
źródło
We CommonLisp istnieje wiele sposobów na ponowne użycie:
dynamiczne pisanie, domyślnie ogólny kod
imperatywne abstrakty, tj. podprogramy
orientacja obiektowa, z wielokrotnym dziedziczeniem i wielokrotną wysyłką
abstrakcja składni, zdolność do definiowania nowych konstrukcji syntaktycznych lub skrótu kodu tablicy kotła
abstrakcje funkcjonalne, zamknięcia i funkcje wyższego rzędu
Jeśli spróbujesz porównać środowisko CommonLisp z innymi językami, zobaczysz, że główną funkcją, która ułatwia ponowne użycie kodu, jest obecność zarówno obiektowych, jak i funkcjonalnych abstrakcji. Są bardziej komplementarne niż alternatywa: bez żadnej z nich jesteś zmuszony do ponownego zaimplementowania brakujących funkcji w niezdarny sposób. Zobacz na przykład klasy funktorów używane jako zamknięcia i dopasowywanie wzorca, aby uzyskać wysyłkę metody nierozszerzalnej.
źródło
- Kevlin Henney
źródło
Zaryzykuję wyśmiewanie i przyznanie się, że używałem OOP dopiero niedawno. Nie przychodzi do mnie automatycznie. Większość mojego doświadczenia dotyczy relacyjnych baz danych, więc myślę w tabelach i złączeniach. Istnieją twierdzenia, że lepiej jest uczyć się od samego początku, co pozwala uniknąć konieczności zmiany sposobu myślenia podczas programowania. Nie mam tego luksusu i nie chcę rezygnować z kariery w oparciu o teorię z kości słoniowej. Jak wszystko inne, wymyślę to.
Na początku myślałem, że cała koncepcja nie ma sensu. Wydawało się to po prostu niepotrzebne i stanowiło zbyt duży problem. Wiem, że to szalona rozmowa. Oczywiście potrzeba pewnego poziomu zrozumienia, aby docenić zalety czegokolwiek lub odrzucić je dla lepszych metod.
Ponowne użycie kodu wymaga chęci nie powtarzania kodu, zrozumienia, jak go osiągnąć, planowania z góry. Czy powinieneś unikać ponownego wykorzystywania kodu, gdy zdecydowałeś, że masz przypadek, w którym nie warto? I żaden język nie jest tak ściśle OO, że zgłasza błąd, gdy myśli, że powinieneś odziedziczyć kod z innej klasy. W najlepszym wypadku zapewniają środowisko sprzyjające jego wdrożeniu.
Myślę, że największą zaletą OOP jest ogólna akceptacja sposobu organizacji kodu. Cała reszta to sos. Zespół programistów może nie do końca uzgodnić strukturę wszystkich klas, ale powinien być w stanie znaleźć kod.
Widziałem wystarczająco dużo kodu proceduralnego, aby wiedzieć, że może być gdziekolwiek, a czasem wszędzie.
źródło
OOP daje więcej możliwości ponownego wykorzystania kodu. To wszystko.
źródło
Ponowne wykorzystanie w poziomie: aspekty, cechy, przeszczepy
Klasyczne OO czasami nie pozwala na ponowne użycie kodu, szczególnie gdy oszalejesz w dziedziczeniu z powodu braku lepszego sposobu na dzielenie się rzeczywistą funkcjonalnością między klasami. Dla tego problemu stworzono poziome mechanizmy ponownego wykorzystania, takie jak AOP, cechy i przeszczepy.
Programowanie aspektowe
Uważam AOP za brakującą połowę pomarańczy OOP. AOP nie jest tak naprawdę znany, ale dotarł do kodu produkcyjnego.
Spróbuję to wyjaśnić prostymi słowami: wyobraź sobie, że możesz wstrzykiwać i filtrować funkcjonalność za pomocą specjalnej struktury zwanej aspektem, te aspekty mają „metody”, które określają, co i jak będzie miało wpływ na odbicie , ale w czasie kompilacji , proces ten nazywa się tkaniem .
Przykładem może być aspekt, który mówi „dla wszystkich metod niektórych klas, które zaczynają się od get, program zapisze w pliku dziennika dane, które zostały pobrane i czas, w którym zostały one uzyskane”.
Obejrzyj te dwa rozmowy, jeśli chcesz lepiej zrozumieć AOP:
Cechy i przeszczepy
Cechy to kolejna konstrukcja do definiowania kodu wielokrotnego użytku, który uzupełnia OOP, są one podobne do mixin , ale czystsze.
Zamiast ich wyjaśniać, istnieje świetny PHP RFC, który wyjaśnia oba . Cechy nadchodzą do PHP btw, są już one zaangażowane w trunk.
W podsumowaniu
Moim zdaniem OOP jest kluczem do modułowości i jak powszechnie wiemy dzisiaj, OOP jest wciąż niekompletny .
źródło
OOP Udostępnia zestaw przydatnych narzędzi, które umożliwiają pisanie kodu, którego można użyć w większej liczbie miejsc niż można bez nich. Jeśli napiszesz
PrintIt
funkcję, która pobiera dowolny stary obiekt i wywołuje.toString()
go, ponownie użyjesz tego kodu, gdy tylko wywołasz go z więcej niż jednym typem obiektu. Dzięki tym narzędziom każdy wiersz kodu robi więcej.Programowanie funkcjonalne jest teraz bardzo popularne wśród hipsterów. Zapewnia ci cały oddzielny zestaw narzędzi, dzięki którym każda linia kodu robi więcej. Prawdopodobnie nie jest lepszy lub działa, ale zapewnia inne narzędzie w przyborniku.
(Był szalony pomysł na cały dodatkowy poziom ponownego użycia obiektowego: Pomysł polegał na tym, że możemy zdefiniować jedną
Customer
klasę i używać jej w każdej napisanej przez nas aplikacji. Wtedy aplikacje byłyby tylko odrobiną kleju tu i tam. To nie działało. Ale to nie znaczy, że OO nie powiodło się, a nawet, że ponowne użycie nie powiodło się. Podstawowe typy ponownego użycia kodu w aplikacjach umożliwiły pisanie aplikacji, które zrobiły więcej, i pisanie ich szybciej).źródło
Czytając powyższe posty, kilka uwag:
źródło
Problemem jest bardziej subtelne imho:
Więc OOP sama w sobie nie jest złe z POV dokonywania kod wielokrotnego użytku , ale rodzaje kodu uzyskać napisane przy użyciu OOP są z natury trudne do ponownego użycia .
Ponadto programowanie funkcjonalne może skutkować kodem wielokrotnego użytku . Ale uzyskanie poprawności abstrakcji do napisania rozsądnego kodu funkcjonalnego podczas dotrzymywania terminu może nie być wykonalne. „Półprawidłowe” abstrakcje będą łatwiej wyrazić styl OOP. I nie będzie miało to skłonności do łatwiejszego ponownego wykorzystania kodu - wyższy poziom abstrakcji oznacza, że zrozumienie kodu będzie wymagało wyższych inwestycji z uwagi na ograniczoną zdolność poznawczą programistów.
Jako praktyczny przykład: kod gry wiąże się z wieloma zmiennymi stanami, ponieważ jest to naturalny sposób myślenia o kodowaniu gry, chyba że jest to bardzo zagadkowa / algorytmiczna, więc oczywiście kończy się na strukturze OO. I oczywiście trudno jest ponownie użyć. Ale ten sam kod, zawierający tę samą wiedzę, byłby jeszcze trudniejszy do ponownego użycia bez OOP . A przepisanie go tak, aby był funkcjonalnym stylem, może wymagać całkowitej zmiany sposobu myślenia o tym kodzie i wiedzy, która się za nim kryje. Tak, wiedza wynikająca z tego kodu byłaby znacznie jaśniejsza po przepisaniu OO na FP, może ... ale koszt może być ogromny i może byćkoszty, które musieliby ponieść osoby, które chcą ponownie wykorzystać niewiarygodnie inteligentny i dobrze wyodrębniony kod, którym się ostatecznie posługujesz , więc paradoksalnie ludzie ostatecznie nie wykorzystaliby tego kodu, nawet jeśli technicznie jest to bardziej przydatne.
... co prowadzi do ostatniej subtelności: ponowne użycie kodu dotyczy interfejsu People | Code , a nie tylko kodu. OOP wykonuje przyzwoitą robotę, obsługując ten interfejs, ponieważ dobrze odwzorowuje to, ile osób myśli o wielu rodzajach pisanych obecnie kodów. FP może być lepszy do ponownego użycia kodu, ale imho nie do łatwego ponownego użycia kodu, który ludzie tak naprawdę potrzebują obecnie pisać. Zmieni się to jako rodzaj kodu, którego potrzebujemy do pisania zmian.
PS I jeśli ktoś chce powiedzieć, że „OO nie dotyczy stanu zmiennego, możesz również mieć OO ze stanem niezmiennym”… Nazywam to „FP za pomocą klas jako przestrzeni nazw”. Jest świetny, gdy działa dla Ciebie i pozwala uniknąć pewnych niedociągnięć w systemach modułów niektórych języków i może skutkować większą liczbą kodów wielokrotnego użytku. Ale to nie OO;)
źródło