Jakie jest uzasadnienie posiadania obiektów towarzyszących w Scali?

Odpowiedzi:

82

Obiekt towarzyszący w zasadzie zapewnia miejsce, w którym można umieścić metody „statyczne”. Ponadto obiekt towarzyszący lub moduł towarzyszący ma pełny dostęp do elementów członkowskich klasy, w tym do prywatnych.

Obiekty towarzyszące doskonale nadają się do hermetyzacji rzeczy, takich jak metody fabryczne. Zamiast na przykład Fooi FooFactorywszędzie, możesz sprawić, by klasa z obiektem towarzyszącym przejęła obowiązki fabryki.

Saem
źródło
61

Obiekty towarzyszące są przydatne do przechowywania stanu i metod, które są wspólne dla wszystkich wystąpień klasy, ale nie używają statycznych metod ani pól. Używają zwykłych metod wirtualnych, które można zastąpić przez dziedziczenie. Scala naprawdę nie ma nic statycznego. Można to wykorzystać na wiele sposobów, ale oto prosty przykład.

abstract class AnimalCounter
{
    var animals = 0

    def name: String

    def count()
    {
        animals += 1
        println("%d %ss created so far".format(animals, name))
    }
}

abstract class Animal
{
    def companion: AnimalCounter
    companion.count()
}

object Dog extends AnimalCounter
{
    val name = "dog"
}

class Dog extends Animal
{
    def companion = Dog
}

object Cat extends AnimalCounter
{
    val name = "cat"
}

class Cat extends Animal
{
    def companion = Cat
}

Który generuje ten wynik:

scala> new Dog
1 dogs created so far

scala> new Cat
1 cats created so far

scala> new Dog
2 dogs created so far

scala> new Cat
2 cats created so far
Craig P. Motlin
źródło
1
podobną ilustrację można znaleźć również tutaj: daily-scala.blogspot.sk/2009/09/companion-object.html
xhudik
30

... i jest to dobre miejsce do przechowywania statycznych metod fabrycznych (nie DP) dla klas towarzyszących. Jeśli nazwiesz te przeciążone metody fabryczne Apply (/ ... /), będziesz mógł utworzyć / zainicjować swoją klasę

  1. bez „nowego” (niezbyt ważne)

  2. z różnymi możliwymi zestawami parametrów (porównaj z tym, co Bloch pisze w Effective Java o konstruktorze teleskopowym)

  3. z możliwością decydowania, którą klasę pochodną chcesz utworzyć zamiast abstrakcyjnej (towarzyszącej)

Przykładowy kod:

abstract class AbstractClass;
class RealThing(s: String) extends AbstractClass;
class AlternativeThing(i: Int) extends AbstractClass;
object AbstractClass {
  def apply(s: String) = {
    new RealThing(s)
  }
  def apply(i: Int) = {
    new AlternativeThing(i)
  }
}

// somewhere else you can
val vs = AbstractClass("asdf")  // gives you the RealThing wrapped over string
val vi = AbstractClass(123)  // gives you AlternativeThing wrapped over int

Nie nazwałbym obiektu / klasy bazowej AbstractXxxxx, ponieważ nie wygląda to źle: jak tworzenie czegoś abstrakcyjnego. Nadaj tym imionom prawdziwe znaczenie. Rozważ użycie niezmiennych, mniej metod, klas przypadków i uszczelnij abstrakcyjną klasę bazową.

Szymon Jachim
źródło
2
RealThingi AlternativeThingklasa powinny mieć privatekonstruktora, który zmusi użytkownika do korzystania z AbstractClassfabryki has. class AlternativeThing private(i: Int) extends AbstractClass
metch
@ [Szymon Jachim] Klasa abstrakcyjna Scala nie obsługuje dziedziczenia wielokrotnego. Dlaczego więc kompilator pozwala na to w twoim przypadku?
user2441441
19

Oprócz tego, co powiedział Saem w swojej odpowiedzi , kompilator Scala szuka również niejawnych konwersji typów w odpowiednich obiektach towarzyszących (źródłowych lub docelowych), więc konwersje nie muszą być importowane.

O przyczynie pojedynczych obiektów w ogólnym Programowaniu w Scali mówi:

Jak wspomniano w rozdziale 1, jednym ze sposobów, w jaki Scala jest bardziej zorientowana obiektowo niż Java, jest to, że klasy w Scali nie mogą mieć statycznych elementów członkowskich. Zamiast tego Scala ma obiekty pojedyncze (s. 65).

Fabian Steeg
źródło
3

Obiekty towarzyszące zawsze postrzegam jako pomost do pisania kodu funkcjonalnego i obiektowego w Scali. Często potrzebujemy tylko czystych funkcji, które pobierają pewne dane wejściowe i zapewniają wynik przetwarzania. Umieszczenie tych odpowiednich funkcji w obiekcie towarzyszącym ułatwia wyszukiwanie i używanie, zarówno dla mnie, jak i dla kogoś, kto jest oparty na moim kodzie.

Co więcej, jest to funkcja dostępna w języku, która umożliwia pisanie wzorca singleton bez robienia czegokolwiek. Jest to szczególnie przydatne, gdy potrzebujesz singletona do hermetyzacji delegatora na potrzeby życia maszyny JVM. Na przykład napisanie prostej biblioteki klienta HTTP w Scali, w której można hermetyzować podstawowy delegator oparty na implementacji Java i pozwolić konsumentom API żyć w czystym świecie.

Gaurav Abbi
źródło
0

Jeśli zdefiniujesz klasę i obiekt w tym samym pliku o tej samej nazwie, będą one znane jako klasa towarzysząca i obiekt. Scala nie ma słowa kluczowego static jako słowa kluczowego JAVA, możesz zastąpić statyczny klasą towarzyszącą i obiektem w Scali.

Aby uzyskać więcej szczegółowych informacji, sprawdź klasę artykułu i słowo kluczowe obiektu w programowaniu scala

FOD
źródło
-1

Na początku zapewnia wyraźne oddzielenie metod statycznych od metod niestatycznych, a także zapewnia prosty sposób tworzenia klasy pojedynczej.

Może również dziedziczyć metody z innych klas i / lub cech, czego nie można zrobić za pomocą statycznych metod Java. I może być przekazywany jako parametr.

vipin
źródło