Czy istnieje przypadek, w którym potrzebny jest obiekt towarzyszący (singleton) dla klasy? Dlaczego miałbym chcieć utworzyć klasę, powiedzieć, Foo
a także utworzyć dla niej obiekt towarzyszący?
Czy istnieje przypadek, w którym potrzebny jest obiekt towarzyszący (singleton) dla klasy? Dlaczego miałbym chcieć utworzyć klasę, powiedzieć, Foo
a także utworzyć dla niej obiekt towarzyszący?
Odpowiedzi:
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 Foo
i FooFactory
wszędzie, możesz sprawić, by klasa z obiektem towarzyszącym przejęła obowiązki fabryki.
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
... 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ę
bez „nowego” (niezbyt ważne)
z różnymi możliwymi zestawami parametrów (porównaj z tym, co Bloch pisze w Effective Java o konstruktorze teleskopowym)
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ą.
RealThing
i AlternativeThing
klasa powinny mieć private
konstruktora, który zmusi użytkownika do korzystania z AbstractClass
fabryki has. class AlternativeThing private(i: Int) extends AbstractClass
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).
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.
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
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.