2011-10-27 13 views
7

Odczytując niektóre z mojego kodu Scala, zauważyłem, że jest on albo funkcjonalny, albo zorientowany obiektowo.Jak łączyć rzekomo niezgodne paradygmaty: OOP i FP?

W istocie nie mam pojęcia, jak pogodzić się z zasadą efektów niepochodzących, domniemanych przez niezmienne typy i czyste funkcje oraz założenie OO, gdzie metody modyfikują stan instancji w miejscu, co jest oczywiście efektem ubocznym.

Jednym z rozwiązań, które badam, jest sprawienie, by wszystkie metody zwróciły klon aktualnej instancji z odpowiednimi modyfikacjami stanu. Wydaje się być chętny, ale może pomóc, gdy zdecyduję się na paralelizację kodu, prawda?

Jakie są najlepsze praktyki dotyczące mieszania tych dwóch paradygmatów? Jaka jest równowaga?

Dzięki.

+2

Interesujące i bardzo powiązane ze sobą brzmienie: [Czy FP i OO są ortogonalne?] (Http://stackoverflow.com/q/3949618/395760) – delnan

+4

Czy to przesłanie OO? Dlaczego więc efektywna Java zaleca niezmienne obiekty? Myślę, że powinieneś zacząć uzgadniać swój pogląd na OO z tym, co rzeczywiście mówili eksperci ... –

Odpowiedz

2

Chyba faktycznie nie zgadzają się ze sposobem jesteś oprawy to:

Rzeczywiście, nie mam pojęcia, w jaki sposób pogodzić się z no-Side Effects implikowane przez regułę niezmiennych typów i czystych funkcji i przesłankę OO, w której metody modyfikują stan instancji w miejscu, co jest oczywiście efektem ubocznym.

Nie powiedziałbym, że operacje mutacyjne na polach obiektów są rdzeniem "założenia OO". Wcale nie (chociaż odwrotnie: I do uważam, że niezmienność jest podstawową przesłanką FP). Dla mnie OO jest sposobem myślenia o module programowym bardziej niż cokolwiek innego.

W moim (być może skręconym) sposobie myślenia, nawet Haskell - język, którego zwolennicy często boją się myślenia w stylu OO - niemniej jednak zawiera pewne koncepcje OO, w tym sensie, że ma system modułów, różne sposoby enkapsulacji implementacji szczegóły typów danych itp. Z drugiej strony, chociaż jest wyjątkowo niezgrabny i obciążający, mój kod Java ma tendencję do intensywnego korzystania z podstawowych koncepcji funkcjonalnych, takich jak curry.

Innymi słowy, uważam, że oba podejścia są w pewnym sensie komplementarne.

Teraz na poziomie mniej więcej teoretyczne i orzechy i-śruby ... Powiedzmy, że masz coś takiego:

class Foo(val a : A, val b : B, val c : C) { 
    def setB(newb : B) : Foo = new Foo(a, newb, c) 
} 

... więc można powiedzieć newFoo = foo.setB(b) jak zasugerował w oryginalnym poście . Powiedziałbym, że jest to całkowicie elegancki styl i nie jest powodem do niepokoju (jeśli chodzi o wydajność, czytelność czy cokolwiek innego). Wiele z tego znajdziesz w niezmiennych klasach kolekcji w bibliotece Scala.

+0

Jeśli YU powiedziałeś, że OO jest połączone z Modułowością, możesz opisać, jak to się stało? Jakie funkcje stosuje OO do modułowości Schuss? Pytam, ponieważ jestem ciekawostką i myślę, że jestem prosty i osiągam modułowość. Nie mogę wymyślić użytecznych (wyłącznych) cech OO, które to umożliwiają. Może polimorfizm "a la carte" patrz tutaj: http://www.infoq.com/presentations/Simple-Made-Easy? – AndreasScheinert

0

Możesz chcieć sprawdzić Functional Programming chapter programu do programowania (to jest available free online), aby uzyskać wskazówki.

FP nie chodzi tylko o gwintowanie. Funkcje wysokiego rzędu pomagają oczyścić i osuszyć kod, dzięki czemu wyglądają bardziej elegancko.

+0

Dziękuję za odpowiedź. Jestem w pełni przekonany o korzyściach płynących z FP i zastosowałem je już, ale zastanawiam się nad granicą dwoistości wyrażoną w górnym poście. –

+0

FP nie chodzi o to, by "sprawić, by Twój kod wyglądał elegancko", chodzi o kompozycyjność i modułowość dzięki możliwości ponownego wykorzystania. – AndreasScheinert

+0

cokolwiek powiesz –

7

Klasy niezmienne to bardzo dobry sposób na mostkowanie OO i FP. Scala jest Collection Library jest doskonałym przykładem mieszania OO, niezmiennych obiektów i programowania funkcjonalnego.

W swoim własnym kodzie, Scala case classes naprawdę pomaga w implementacji niezmiennego obiektu, ponieważ ma on metodę copy, która może być użyta jako zamiennik wzorca budowniczego.

// begin cheesy example 
case class Circle(center: (Double, Double), radius: Double) { 
    def move(c: (Double, Double)) = copy(center = c) 
    def resize(r: Double) = copy(radius = r) 
    def area = math.Pi * radius * radius 
} 

Można również skorzystać obserwując rozmowy Rich Hickey Persistent Data Structures and Managed References i Are We There Yet? Obaj wykonują świetną robotę, tłumacząc potrzebę niezmienności i pomagając nam wnioskować o stanie. Mówi o wszystkim w odniesieniu do Clojure, ale jego punkty odnoszą się równie dobrze do Scali.

0

make wszystkie metody powrotu klon bieżącej instancji

sprawdzając jak jQuery to robi, to wykorzystuje technikę zwaną metodą Chaining każda metoda, która w przeciwnym razie zwraca void powraca $ to tak możesz nadal wywoływać metody jeden nad drugim. Właśnie dlatego obiektowość jQuery nie łamie tradycyjnego proceduralnego kodu użytkownika w javascript.