Prywatny i chroniony konstruktor w Scali

109

Byłem ciekawy wpływu braku jawnego głównego konstruktora w Scali, a jedynie zawartość treści klasy.

W szczególności podejrzewam, że wzorzec konstruktora prywatnego lub chronionego, czyli sterowanie konstrukcją za pomocą obiektu towarzyszącego lub innej klasy lub metod obiektu, może nie mieć oczywistej implementacji.

Czy się mylę? Jeśli tak, jak to się robi?

Don Mackenzie
źródło
Możesz mieć singleton Scala (ze słowem kluczowym object, to znaczy) i zdefiniować swoją klasę jako prywatną w tym singletonie i mieć metody singletona do konstruowania obiektów.
Paggas
@Paggas, niestety, gdy zwrócisz wystąpienie klasy oznaczonej jako prywatna poza jej zakresem, nie zostanie ona skompilowana, nawet jeśli zostanie zwrócona z metody jej obiektu towarzyszącego w zakresie.
Don Mackenzie
Robi się to dość obszernie w całym kodzie źródłowym Scalaz. Pojęcie to jest również znane jako abstrakcyjny algebraiczny typ danych.
Tony Morris

Odpowiedzi:

190

Możesz zadeklarować domyślny konstruktor jako prywatny / chroniony, wstawiając odpowiednie słowo kluczowe między nazwą klasy a listą parametrów, na przykład:

class Foo private () { 
  /* class body goes here... */
}
Aleksander Kmetec
źródło
Dzięki Aleksandrze, czy możesz mi powiedzieć, czy jest to przedstawione w jednej z książek scala, czy w specyfikacji języka? Przepraszam, nie mogę jeszcze zagłosować.
Don Mackenzie
Właśnie przejrzałem wyjaśnienie konstruktorów w „Programming Scala” (strony 92-95) i nie widzę, żeby tam było wspomniane. Właściwie znalazłem odpowiedź na twoje pytanie w starym dzienniku zmian, ale nigdy wcześniej nie widziałem, aby o niej wspomniano. Link: scala-lang.org/node/43#2.4.0
Aleksander Kmetec
18
Pag 414 "Programowanie w Scali". Strona 97 Scali programowania Wamplera. Strona 60 Scali programowania Subramaniam. Nie mam w tej chwili pliku PDF Beginning Scala, aby to sprawdzić.
Daniel C. Sobral
Och, widzę to teraz na stronie 97. Dzięki.
Aleksander Kmetec
1
Dziękuję obojgu za dalsze badania, mam książkę Wamplera, ale tylko na telefonie i najwyraźniej nie przeczytałem jej dokładnie, ale stwierdziłem, że zaskakująco dobrze uzupełnia książkę Odersky'ego.
Don Mackenzie
64

Odpowiedź Aleksandra jest prawidłowa, ale programowanie w Scali oferuje dodatkową alternatywę:

sealed trait Foo {
 // interface
}

object Foo {
  def apply(...): Foo = // public constructor

  private class FooImpl(...) extends Foo { ... } // real class
}
Daniel C. Sobral
źródło
18
Pojawił się po latach, by powiedzieć: myślę, że to dobra odpowiedź na pytanie, ale złe rozwiązanie problemu. Gdyby jakiś przyszły programista był w kodzie Aleksandra, powiedziałby: „Ach, główny konstruktor jest prywatny, a inni nie”. Gdyby ten programista spojrzał na kod Daniela, powiedziałby: „Ach, używają wzorca Factory, aby skompensować niezdolność Scali do oznaczenia domyślnych konstruktorów jako prywatnych. Czekaj, Scala może oznaczyć domyślne konstruktory jako prywatne! Co się dzieje? tutaj?!?" Innymi słowy, zły stosunek WTF / LOC.
Malvolio
20
@Malvolio Nie do końca się zgadzam. Ten wzorzec nie tylko sprawia, że ​​główny konstruktor jest prywatny, ale także implementacja , zmuszając użytkownika do korzystania z interfejsu (cechy). To ma swoją wartość. A jeśli ktoś coś myśli, bo nie zna języka - bzdury! Cytując Kenny'ego Tiltona, naucz się tego cholernego języka !
Daniel C. Sobral
7
Należy gdzieś wspomnieć, że takie podejście oznacza nieużywanie newsłowa kluczowego.
Travis Parks,
1
Jedynym zastrzeżeniem związanym z tym podejściem jest to, że ktoś może nadal utworzyć wystąpienie Foo za pośrednictwem własnej implementacji. Może to być postrzegane jako zaleta lub wada w zależności od powodu kontrolowania konstrukcji.
aij
1
@aij Prawda, więc zrobiłem to tak, że nie może się już więcej zdarzyć. :)
Daniel C. Sobral