2010-02-08 21 views
36

w Scala, widziałem konstruktyRóżnica między cecha dziedziczenia i rodzaju własnej adnotacji

trait T extends S 

i

trait T { this: S => 

wykorzystane do osiągnięcia podobnych rzeczy (a mianowicie, że abstrakcyjne metody S musi być zdefiniowane przed utworzeniem instancji). Jaka jest między nimi różnica? Dlaczego używałbyś jednego nad drugim?

+9

Dokładny duplikat http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclasses, który jest pierwszym pytaniem wyświetlonym na powiązanej liście . –

Odpowiedz

12

Używałbym self-types do zarządzania zależnościami: Ta cecha wymaga mieszania innej cechy. I użyłbym dziedziczenia do udoskonalenia innej cechy lub interfejsu.

Tylko jako przykład:

trait FooService 

trait FooRemoting { this : FooService => } 
trait FooPersistence { this : FooService => } 

object Services extends FooService with FooRemoting with FooPersistence 

Teraz, jeśli FooRemoting i FooPersistence zarówno byłby odziedziczone FooService i FooService ma członków i sposobów, w jaki sposób usługi wyglądać?

Podczas gdy dla dziedziczenia, musielibyśmy coś takiego:

trait Iterator[T] { 
    def hasNext : boolean 
    def next : T 
} 

trait InfiniteIterator[T] extends Iterator[T] { 
    def hasNext = true 
} 
+16

Przepraszam Victor, nie rozumiem "jak wyglądałyby Usługi?" część. Próbowałem obu sposobów i widzę, że obiekt usług zachowuje się tak samo. Jaka jest sytuacja, która sprawia, że ​​różnica jest oczywista? – ithkuil

25

zaworem adnotacje pozwalają wyrazić zależności cykliczne. Na przykład:

trait A extends B 
trait B { self: A => } 

Nie jest to możliwe przy prostym dziedziczeniu.

+0

czy masz przypadki użycia? – crak

+0

Możesz użyć tej techniki do naśladowania klas częściowych, jak w C#. Zobacz na przykład https://msdn.microsoft.com/en-us/library/wa80x488.aspx. –

6

Ponieważ zadajesz pytanie natknąłem tych stanowisk:

Spiros Tzavellas rozmowy o użyciu cechę jak interfejsie publicznym i typu siebie jako pomocnik, które muszą być zmieszane w przez klasę realizacji.

Podsumowując, jeśli chcemy przenieść implementacje metod wewnątrz cech wtedy ryzykujemy zanieczyszczających interfejs tych cech z abstrakcyjnych metod które wspierają realizację konkretnych metod i niezwiązane z głównym odpowiedzialność za cechę . Rozwiązaniem tego problemu jest przeniesienie tych abstrakcyjnych metod w inne cechy i skomponowanie ich razem przy użyciu adnotacji typu self i wielokrotnego dziedziczenia.

Na przykład:

trait PublicInterface { this: HelperTrait => 
    // Uses helperMethod 
} 

trait HelperTrait { 
    def helperMethod = // ... 
} 

class ImplementationClass extends PublicInterface with HelperTrait 

A Tour of Scala omawia użycie zaworem adnotacje z abstrakcyjnych elementów typu - przypuszczalnie nie jest możliwe do extend streszczenie członkiem typ

+0

to wróć, nie? Powinien być "class ImplementationClass rozciąga HelperTrait z PublicInterface"; to znaczy, cecha musi być wymieszana w pierwszej kolejności przed odniesieniem jej jako typu własnego – virtualeyes

+0

Wydaje mi się, że jest to zły projekt. Metody pomocnicze są zagadnieniem związanym z implementacją podklas programu 'PublicInterface'. Dlaczego po prostu nie używać metod "chronionych"? –

1

Chociaż nie odpowiada (?) Twoje pytanie, starałem się zrozumieć adnotacje typu self i zasadniczo zagubiłem się w odpowiedziach, i jakoś skończyłem na cyklach poprzez różne warianty twojego pytania, które koncentrują się na używaniu adnotacji self-type do opisywania zależności.

Więc tutaj zamieścić opis danego przypadku użycia gdzie jaźń typu adnotacje są dobrze ilustrowany, czyli coś podobnego przypadku type-safe z „tym” jako podtyp:

http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers

nadzieję, że Byłoby to pomocne dla tych, którzy przypadkowo trafiają na to pytanie (i, tak jak ja, nie mieli czasu na przeczytanie książki o scali przed rozpoczęciem eksploracji :-))

+0

Zmienili linki. Teraz jest: http://ofps.oreilly.com/titles/9780596155957/ApplicationDesign.html (w "Adnotacjach self-type i członach typu abstract", bez bezpośredniego linku) – akauppi

2

Odpowiedź brzmi "okrągłość". Ale nie tylko.

Adnotacja typu self rozwiązuje dla mnie podstawowy problem dziedziczenia: to, z czego odziedziczysz, nie może używać tego, czym jesteś. Dzięki samemu typowi wszystko staje się łatwe.

mój wzór jest następujący i można go traktować jako zdegenerowanego ciasto:

trait A { self: X => def a = reuseme} 
trait B { self: X => def b = a } 
class X extends A with B { def reuseme=null } 

Możesz wybuchnąć klasę w wielu zachowań, które mogą być wywoływane z dowolnego miejsca w zespole, podczas pobytu czysto wpisane. Nie trzeba zbyt często bolesnego kierowania (i niesłusznie) identyfikować z wzorcem ciasta.

Połowa (jeśli nie całość) zawiłych frameworków Java DI z ostatnich dziesięciu lat została poświęcona temu procesowi, oczywiście bez pisania. Osoby wciąż używające JAVA w tej domenie wyraźnie tracą swój czas: "SCALA ouakbar".