2013-06-13 23 views
7

moje pytanie dotyczy sposobu radzenia sobie z dziedziczeniem w sposób funkcjonalny w języku F #. Aby to trochę opisać, podaję prosty przykład. Załóżmy, że chcemy modelować świat składający się z różnych gatunków zwierząt. Każdy rodzaj zwierząt ma pewne atrybuty z innymi rodzajami (np. Nazwa, rozmiar itp.). Ponadto każdy rodzaj może mieć inne, które nie są dzielone przez inne osoby (np. Liczba dzieci jest odpowiednia dla psów i kotów, jednak na przykład dla pająków). Ponadto, mogą istnieć sposoby lub funkcje związane z każdym typem zwierzęcia, które mogą być lub nie być takie same dla dwóch rodzajów zwierząt, tj. Istnieje domyślna implementacja, która może być pominięta dla określonego rodzaju. Każdy rodzaj zwierząt może mieć metodę (metody), która jest zdefiniowana tylko dla tego rodzaju.F # i modelowanie dziedziczenia

Teraz, w świecie OOP, prawdopodobnie doprowadziłoby to do powstania klasy abstrakcyjnej o wspólnych cechach i abstrakcyjnych metodach, a następnie klasach pochodnych dla każdego rodzaju zwierząt. Nie jestem pewien, jak określić funkcjonalnie model domeny w F #. Tutaj: Which to use , abstract class or interface in F#? jest twierdził, że "idiomatyczny kod F # używa różnych punktów rozszerzalności niż C# (np. Przyjmując funkcję/interfejs jako argument), więc naprawdę nie potrzebujesz klas abstrakcyjnych".

Jeśli jest to sposób, który powinien zostać przyjęty, czy można podać jakiś element tego przykładu?

Jeśli chodzi o moje dalsze rozważania na ten temat, przypuszczam, że atrybuty powinny być zamknięte w pewnej strukturze. Wtedy najbardziej idiomatyczna struktura pod tym względem w F # jest rekordowa. Czy to oznacza, że ​​ma istnieć zapis nadrzędny, który będzie zawarty w innych zapisach odpowiadających konkretnym "dzieciom", tj. Kompozycji zamiast dziedziczeniu. Wydaje mi się to jednak rozwiązaniem tymczasowym, które nie jest ani idiomatyczne, ani szczególnie eleganckie.

Myślę, że preferowanym sposobem modelowania dziedziczenia w F # są dyskryminowane związki. Jednak nie rozwiązuje to problemu wspólnych atrybutów i metod.

Modele podobne do wspomnianych powyżej są dość częste w moim widoku, ponieważ są domyślnie zawarte w większości aplikacji dla przedsiębiorstw. Czy jest więc jakaś sugestia, jak można to potraktować w sposób funkcjonalny (np. Sposób sugerowany pod powyższym linkiem lub jakakolwiek inna sugestia)? Czy możemy powiedzieć, że nie jest to domena, którą można łatwo modelować za pomocą podejścia funkcjonalnego?

Dziękuję.

Odpowiedz

9

Twój opis przykładu już zakłada obiektowy model programowania. Opisujesz problem w kategoriach obiektowych, takich jak nadpisywanie i metody zdefiniowane dla określonych typów zwierząt. To sprawia, że ​​trudno jest dać sensowną alternatywną reprezentację funkcjonalną, ponieważ twoje pytanie już zakłada koncepcje obiektowe w odpowiedzi.

Po pierwsze, idealnie jest używać konstruktów zorientowanych obiektowo w języku F #, gdy mają one sens (przykład w pytaniu jest po prostu próbką zabawki, więc może tak być lub nie). Kluczową ideą jest to, że F # woli kompozycję niż dziedziczenie, więc prawdopodobnie spróbowałbyś uniknąć dziedziczenia (co może prowadzić do złożonych hierarchii obiektów) i zamiast tego komponować zwierzęta z różnych aspektów.

Po drugie, jeśli wyjaśniłeś swój problem w inny sposób, to może istnieć perfekcyjnie reprezentacja funkcjonalna za pomocą dyskryminowanych związków. Na przykład:

type MammalKind = Cat | Dog 
type MammalInfo = { Legs : int; Children : int } 

type Animal = 
    | Mammal of MammalKind * MammalInfo 
    | Spider of (...) 

Pomysł byłoby zorganizować typ tak, że różne rodzaje zwierząt (które można przetwarzać w inny sposób) mają swój własny rodzaj.Na przykład można napisać funkcję, która pobiera MammalInfo i wykonuje pewne obliczenia, które mają sens tylko dla psów i kotów (ale nie dla pająków). Ale jak wspomniałem wcześniej, twój opis problemu jest z natury rzeczy zorientowany na obiekt, więc może być trudno zobaczyć, jak to się stało.

+0

Dobre pytanie, wspaniała odpowiedź! – mydogisbox

+0

Odpowiedź Tomasa Petricka jest bardzo dobra. Chciałbym również polecić następującą odpowiedź Normana Ramseya: http://stackoverflow.com/a/2079678/631115. – Shredderroy

+0

Tomas, dziękuję za przykład. To jest ładne i proste. Jeśli chodzi o opis, który podałem, starałem się wyraźnie odróżnić opis i możliwą implementację (klasa abstrakcyjna). Zastanawiam się, czy wspólne funkcje (np. Funkcja zwracająca nazwę zwierzęcia w jakiś fantazyjny sposób - dla wszystkich zwierząt - lub niektóre współczynniki dla dzieci - dla wszystkich ssaków) mają być częścią poszczególnych typów (AnimalInfo - które jeszcze zostałyby utworzone) oraz MammalInfo) jako jego członkowie lub bez względu na to, czy deklarują je swobodnie (nie są przypisani). Uważam również, że jest to pytanie bardziej ogólne, niezwiązane wyłącznie z typem kompozycji. – user2039784