OOP vs programowanie funkcjonalne vs proceduralne [zamknięte]


237

Jakie są różnice między tymi paradygmatami programowania i czy są one lepiej dostosowane do konkretnych problemów, czy też jakieś przypadki użycia faworyzują jeden nad drugim?

Docenione przykłady architektury!


To nie jest pełna odpowiedź, ale piszę trochę o tym, jak „funkcjonalny” wpływa / kontrastuje ze stylem „OO” (w kontekście F #) tutaj: lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!511. wstęp
Brian

Możesz to przeczytać ! Istnieje wiele przykładów użycia mrówki, jakie są główne różnice, zalety / wady itp.
Nikita Ignatov



Wujek Bob napisał o tym na Twitterze . A także tutaj .
jaco0646

Odpowiedzi:


129

Wszyscy są dobrzy na swój sposób - są po prostu innym podejściem do tych samych problemów.

W czysto proceduralnym stylu dane są zwykle bardzo oddzielone od funkcji, które na nich działają.

W stylu obiektowym dane zwykle niosą ze sobą zbiór funkcji.

W stylu funkcjonalnym dane i funkcje mają tendencję do posiadania większej liczby wspólnych elementów (jak w Lisp i Scheme), oferując jednocześnie większą elastyczność pod względem faktycznego wykorzystania funkcji. Algorytmy zwykle definiuje się także w kategoriach rekurencji i kompozycji, a nie pętli i iteracji.

Oczywiście sam język wpływa tylko na preferowany styl. Nawet w czysto funkcjonalnym języku, takim jak Haskell, możesz pisać w stylu proceduralnym (choć jest to bardzo odradzane), a nawet w języku proceduralnym, takim jak C, możesz programować w stylu obiektowym (takim jak GTK + i EFL API).

Mówiąc jasno, „zaletą” każdego paradygmatu jest po prostu modelowanie algorytmów i struktur danych. Jeśli na przykład twój algorytm obejmuje listy i drzewa, algorytm funkcjonalny może być najbardziej sensowny. Lub, na przykład, jeśli twoje dane są wysoce ustrukturyzowane, bardziej sensowne może być skomponowanie ich jako obiektów, jeśli jest to natywny paradygmat twojego języka - lub równie łatwo można je zapisać jako funkcjonalną abstrakcję monad, które jest rodzimym paradygmatem języków takich jak Haskell lub ML.

Wybór, którego używasz, jest po prostu tym, co ma większy sens dla twojego projektu i abstrakcji obsługiwanych przez Twój język.


5
To, co powiedziałeś, nie odzwierciedla tego, co napisałeś. Mówisz, że nie mają „plusów i minusów”, a następnie mówisz, jak różnią się od siebie. Dlaczego ktoś miałby wybierać jedno podejście zamiast drugiego, w zależności od danej sytuacji? mocne i słabe strony, zalety i wady, jakkolwiek je nazwiesz, one istnieją! Nie twierdzę, że jeden jest z natury lepszy, podobnie jak ty. Wierzę, że tak naprawdę chciałeś powiedzieć. chyba że naprawdę wierzysz, że jakiekolwiek wybrane podejście nie ma pozytywów i negatywów w stosunku do innego podejścia.
JM Becker,

1
@TechZilla: Zgadzam się, że moje sformułowania były kiepskie, ale miałem na myśli to, że tak naprawdę nie ma listy funkcji, które można wskazać i powiedzieć, że język X jest lepszy niż Y bez kwalifikacji, że język X lepiej nadaje się do pisania algorytmu U i języka Y może być lepiej przystosowany do pisania algorytmu V, podczas gdy oba można łatwo zaimplementować w dowolnym języku.
greyfade

2
Różnica między proceduralnym a funkcjonalnym nie jest dla mnie jasna. Uczę się Scheme / Rackett w College, ale naprawdę nie widzę dużej różnicy między nim a proceduralnym C lub PHP, czy możesz podać jakiś przykład?
Leonel

7
@Leonel: Największą różnicą, którą przytoczy większość ludzi, jest to, że w językach proceduralnych możesz użyć pętli for, ale w językach funkcjonalnych nie ma czegoś takiego - zamiast tego używasz rekurencyjnych wywołań funkcji do wykonania tego samego zadania. Języki funkcjonalne tworzą również funkcje pierwszorzędnych obiektów - możesz przekazywać je jak liczbę - ale nie możesz tego robić w C (a obsługa PHP jest zepsuta).
greyfade

2
@tastro: Gdy jeden paradygmat ma większy sens niż drugi. To naprawdę wszystko. Czasami bardziej sensowne jest modelowanie kodu jako kompozycji funkcji, a czasem bardziej sensowne jest modelowanie danych jako obiektów. Istnieje wiele sposobów wyrażania algorytmów i struktur danych. OOP i funkcjonalność to dwie z tych rzeczy.
greyfade

25

Myślę, że dostępne biblioteki, narzędzia, przykłady i społeczności całkowicie przebijają paradygmat w dzisiejszych czasach. Na przykład ML (lub cokolwiek innego) może być najlepszym uniwersalnym językiem programowania , ale jeśli nie możesz dostać żadnych dobrych bibliotek do tego, co robisz, to jesteś zepsuty.

Na przykład, jeśli tworzysz grę wideo, w C ++ jest więcej dobrych przykładów kodu i zestawów SDK, więc prawdopodobnie lepiej ci będzie. W przypadku małej aplikacji internetowej istnieje kilka świetnych frameworków Python, PHP i Ruby, które pozwolą ci szybko uruchomić. Java jest doskonałym wyborem dla większych projektów ze względu na sprawdzanie czasu kompilacji oraz bibliotek i platform korporacyjnych.

Kiedyś standardowe biblioteki dla różnych języków były dość małe i łatwe do replikacji - C, C ++, Asembler, ML, LISP, itp. Były dostarczane z podstawami, ale miały tendencję do drobiazgów, jeśli chodzi o standaryzację rzeczy takich jak komunikacja sieciowa, szyfrowanie, grafika, formaty plików danych (w tym XML), nawet podstawowe struktury danych, takie jak zrównoważone drzewa i tabele skrótów, zostały pominięte!

Współczesne języki, takie jak Python, PHP, Ruby i Java, mają teraz o wiele bardziej przyzwoitą bibliotekę standardową i mają wiele dobrych bibliotek stron trzecich, z których można łatwo korzystać, w dużej mierze dzięki przyjęciu przestrzeni nazw, aby biblioteki nie kolidowały ze sobą, oraz wyrzucanie elementów bezużytecznych w celu ustandaryzowania schematów zarządzania pamięcią bibliotek.


5
Python, ruby, ... nie mają „standardowych” bibliotek, takich jak C lub LISP, ponieważ są to pojedyncze języki implementacji. Python to, co mówi Guido, nie ma standardu. Każda konkretna implementacja C lub LISP (lub cokolwiek) obecnie ma duży zestaw bibliotek poza standardowymi.
Dan Andreatta

8
Pytanie dotyczyło różnic między programowaniem obiektowym, funkcjonalnym i proceduralnym. Podczas gdy języki wymienione w tych odpowiedziach z pewnością nadają się do jednego z tych podejść, odpowiedź nie wspomina o żadnym z tych pojęć ... Niezależnie od tego, czy „dostępne biblioteki [...] [atut] paradygmat”, to nie odpowiada na pytanie, a tym samym odsuwa na bok to, co jest całkowicie uzasadnione.
rinogo

1
Rant związany z ircmaxell
rinogo

20

Te paradygmaty nie muszą się wzajemnie wykluczać. Jeśli spojrzysz na python, obsługuje on funkcje i klasy, ale jednocześnie wszystko jest przedmiotem, w tym funkcje. Możesz łączyć i dopasowywać styl funkcjonalny / oop / proceduralny w jednym kawałku kodu.

Mam na myśli to, że w językach funkcjonalnych (przynajmniej w Haskell, jedynym, którego studiowałem) nie ma żadnych stwierdzeń! funkcje są dozwolone tylko w jednym wyrażeniu !! ALE funkcje są pierwszorzędnymi obywatelami, możesz przekazać je jako parametry wraz z szeregiem innych umiejętności. Mogą robić potężne rzeczy za pomocą kilku linii kodu.

Podczas gdy w języku proceduralnym, takim jak C, jedynym sposobem na przekazywanie funkcji jest użycie wskaźników funkcji, a samo to nie umożliwia wielu potężnych zadań.

W Pythonie funkcja jest obywatelem pierwszej klasy, ale może zawierać dowolną liczbę instrukcji. Możesz więc mieć funkcję zawierającą kod proceduralny, ale możesz przekazywać go tak jak języki funkcjonalne.

To samo dotyczy OOP. Język taki jak Java nie pozwala pisać procedur / funkcji poza klasą. Jedynym sposobem na przekazanie funkcji jest zawinięcie jej w obiekt implementujący tę funkcję, a następnie przekazanie tego obiektu.

W Pythonie nie masz tego ograniczenia.


Uważam, że miałeś na myśli „te paradygmaty nie muszą się wzajemnie wykluczać”. Trzy z nich ortogonalne, dlatego idealnie byłoby użyć jednego, 2 lub 3 z nich w jednym programie (jeśli twój język na to pozwala).
Joe Pineda

Tak, chyba wzajemnie się wykluczamy, jest to lepszy termin! dzięki
hasen

14

W przypadku GUI powiedziałbym, że paradygmat zorientowany obiektowo jest bardzo odpowiedni. Okno jest obiektem, pola tekstowe są obiektami, a także przycisk OK. Z drugiej strony rzeczy takie jak przetwarzanie łańcuchów mogą być wykonywane przy znacznie mniejszym nakładzie pracy, a zatem prostsze dzięki prostemu paradygmatowi proceduralnemu.

Nie sądzę, żeby to była kwestia języka. Możesz pisać funkcjonalnie, proceduralnie lub obiektowo w prawie dowolnym popularnym języku, chociaż w niektórych przypadkach może to wymagać dodatkowego wysiłku.


17
Kusiło mnie, by głosować za utrwaleniem błędnego przekonania, że ​​„widżet Object = GUI”, ale powstrzymam się. OOP działa równie dobrze do reprezentowania pojęć abstrakcyjnych, takich jak „UserAccount” lub „PendingSale”, jak i do widocznych elementów interfejsu, takich jak „Window” i „Button”.
Dave Sherohman

5
Napisałem, że okno może być przedmiotem. Jak wyciągnąć wniosek, że stamtąd każdy Obiekt jest oknem? To był tylko przykład. Oczywiście OOP można równie dobrze wykorzystać do modelowania abstrakcyjnych bytów i ich relacji. W każdym razie dzięki za nie oddanie głosu. I tak nie mam wielu punktów: D
panschk

6
-1. OOP nie ma nic wspólnego z GUI. Najlepiej, jeśli najlepszą metodą projektowania guis jest użycie zewnętrznego pliku tekstowego (np. HTML). Podczas gdy rzeczy takie jak przetwarzanie łańcuchów są w rzeczywistości znacznie lepiej wykonywane z obiektami. (pomyśl o ciągach w C) !!
hasen

1
Nie wiem, może jestem przyzwyczajony do programowania obiektami, aby to zrealizować. Ale jak zrobiłbyś jakieś interaktywne rzeczy, takie jak zmiana wartości w TextBox X, gdy wartość TextBox Y została zmieniona bez użycia obiektów? Ok, możesz po prostu użyć globalnych zmiennych do wszystkiego ...
panschk

1
Przetwarzanie napisów jest znakomicie wykonywane w perlu (100 razy lepszym niż w Javie, C ++ lub C #), ale funkcjonalność napisów w języku absolutnie NIE jest zorientowana obiektowo. Obsługa ciągu C była okropna, ale C nie jest jedynym językiem proceduralnym (ani najlepszym).
Joe Pineda

6

Aby odpowiedzieć na twoje pytanie, potrzebujemy dwóch elementów:

  1. Zrozumienie cech różnych stylów / wzorów architektury.
  2. Zrozumienie cech różnych paradygmatów programowania.

Lista stylów / wzorów architektury oprogramowania znajduje się w artykule dotyczącym architektury oprogramowania na Wikipeida. Możesz je łatwo badać w Internecie.

W skrócie, Proceduralna jest dobra dla modelu, który postępuje zgodnie z procedurą, OOP jest dobry do projektowania, a Funkcjonalny jest dobry do programowania na wysokim poziomie.

Myślę, że powinieneś spróbować przeczytać historię każdego paradygmatu i przekonać się, dlaczego ludzie ją tworzą, i możesz je łatwo zrozumieć.

Po zrozumieniu ich obu możesz połączyć elementy stylów / wzorców architektury z paradygmatami programowania.


2

Myślę, że często nie są „przeciw”, ale można je łączyć. Myślę też, że często słowa, o których wspominasz, to tylko modne słowa. Niewiele osób wie, co znaczy „zorientowany obiektowo”, nawet jeśli są najzagorzalszymi ewangelistami.


1

Jeden z moich znajomych pisze aplikację graficzną przy użyciu NVIDIA CUDA . Aplikacja bardzo ładnie wpasowuje się w paradygmat OOP, a problem można starannie rozłożyć na moduły. Jednak aby użyć CUDA, musisz użyć C, który nie obsługuje dziedziczenia . Dlatego musisz być mądry.

a) Opracowujesz sprytny system, który do pewnego stopnia będzie naśladował dziedzictwo. To może być zrobione!

i) Możesz użyć systemu przechwytującego , który oczekuje, że każde dziecko C rodzica P będzie miało pewne przesłonięcie dla funkcji F. Możesz zmusić dzieci do zarejestrowania swoich przesłonięć, które będą przechowywane i wywoływane w razie potrzeby.

ii) Możesz użyć funkcji wyrównania pamięci strukturalnej, aby rzutować dzieci na rodziców.

Może to być fajne, ale nie jest łatwo wymyślić niezawodne rozwiązanie przyszłościowe. Spędzisz dużo czasu na projektowaniu systemu i nie ma gwarancji, że nie napotkasz problemów w połowie projektu. Wdrożenie wielokrotnego dziedziczenia jest jeszcze trudniejsze, jeśli nie prawie niemożliwe.

b) Możesz użyć spójnej polityki nazewnictwa i zastosować podejście dziel i zwyciężaj, aby stworzyć program. Nie będzie dziedziczył, ale ponieważ twoje funkcje są małe, łatwe do zrozumienia i konsekwentnie sformatowane, nie potrzebujesz go. Ilość kodu, który musisz napisać, rośnie, bardzo trudno jest skoncentrować się i nie ulec łatwym rozwiązaniom (włamaniom). Jednak ten sposób kodowania ninja jest sposobem kodowania C. Zachowanie równowagi między swobodą niskiego poziomu a pisaniem dobrego kodu. Dobrym sposobem na osiągnięcie tego jest pisanie prototypów za pomocą funkcjonalnego języka. Na przykład Haskell jest wyjątkowo dobry do algorytmów prototypowania.

Skłaniam się ku podejściu b. Napisałem możliwe rozwiązanie, stosując podejście a, i powiem szczerze, używanie tego kodu było bardzo nienaturalne.


Pierwsze copmpilery c ++ były niczym więcej niż procesorami wstępnymi, które wygenerowały kod C. W związku z tym WSZYSTKIE funkcje c ++ - w tym wielokrotne dziedziczenie, mogą być zaimplementowane przy użyciu C. (emulacja obsługi wyjątków c ++ w C wymagałaby pewnego rodzaju obsługi platformy dla wyjątków, ale implementacje c ++ również tego wymagają, więc nie sądzę, że czyni to podstawową pomysł nieprawidłowy).
Chris Becke

2
@Chris Becke twoja odpowiedź jest zbyt filozoficzna. Po pierwsze, C ma wiele standardów (z biegiem lat), prawie żaden z nich całkowicie nie został zaakceptowany przez kompilatory C, a co dopiero c ++. Powiedzenie, że C ++ jest nadzbiorem języka C, ponieważ używa składni języka C, nie znaczy wiele, ponieważ nie można nawet napisać kodu dla jednego kompilatora C, który kompiluje się w innym kompilatorze C bez znacznego wysiłku. Ponadto istnieją funkcje językowe (systemy typów, obsługa OOD) oferowane w innych językach, których nie można zaimplementować w C bez użycia C do zaprojektowania nowego języka (właśnie dlatego istnieją „nowe języki”)
Sprague,

Wiesz. Nie widzę już żadnego znaczenia mojego komentarza dla tego postu. : P
Chris Becke

Cuda już od jakiegoś czasu wspiera C ++.
Aryeh Leib Taurog
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.