Есть ли случай, когда нужен сопутствующий объект (синглтон) для класса? Зачем мне, скажем, создавать класс, Fooа также создавать для него сопутствующий объект?
Есть ли случай, когда нужен сопутствующий объект (синглтон) для класса? Зачем мне, скажем, создавать класс, Fooа также создавать для него сопутствующий объект?
Ответы:
Сопутствующий объект в основном предоставляет место, где можно разместить «статические» методы. Более того, сопутствующий объект или сопутствующий модуль имеет полный доступ к членам класса, включая частные.
Объекты-компаньоны отлично подходят для инкапсуляции таких вещей, как фабричные методы. Вместо того, чтобы иметь, например, Fooи FooFactoryвезде, вы можете иметь класс с объектом компаньона взять на фабричной обязанности.
Сопутствующие объекты полезны для хранения состояния и методов, общих для всех экземпляров класса, но они не используют статические методы или поля. Они используют обычные виртуальные методы, которые можно переопределить посредством наследования. В Scala действительно нет ничего статичного. Есть много способов использовать это, но вот простой пример.
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
}
Что производит этот вывод:
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
... и это хорошее место для хранения статических фабричных методов (не DP) для сопровождаемых классов. Если вы назовете эти перегруженные фабричные методы apply (/ ... /), вы сможете создать / инициализировать свой класс
без "нового" (не так уж и важно)
с различными возможными наборами параметров (сравните с тем, что Блох пишет в Effective Java о телескопическом конструкторе)
с возможностью решать, какой производный класс вы хотите создать вместо абстрактного (сопровождаемого)
Пример кода:
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
Я бы не стал называть объект / базовый класс AbstractXxxxx, потому что он неплохо выглядит: вроде создания чего-то абстрактного. Придайте этим именам реальный смысл. Рассмотрите возможность использования неизменяемых, безметодных, case-классов и запечатайте абстрактный базовый класс.
RealThingи AlternativeThingкласс должен иметь privateконструктор, чтобы заставить пользователя использовать AbstractClassфабрику has. class AlternativeThing private(i: Int) extends AbstractClass
В дополнение к тому, что Саэм сказал в своем ответе , компилятор Scala также ищет неявные преобразования типов в соответствующих сопутствующих объектах (исходных или целевых), поэтому преобразования не нужно импортировать.
О причине появления одноэлементных объектов в общем программировании на Scala говорится:
Как упоминалось в главе 1, одна из причин, по которой Scala более объектно-ориентирована, чем Java, состоит в том, что классы в Scala не могут иметь статических членов. Вместо этого в Scala есть одноэлементные объекты (стр. 65).
Я всегда рассматриваю сопутствующие объекты как мост для написания как функционального, так и объектно-ориентированного кода на Scala. Часто нам просто нужны чистые функции, которые принимают некоторый ввод и предоставляют результат обработки. Помещение этих соответствующих функций в сопутствующий объект упрощает поиск и использование для меня, а также для кого-то, построенного поверх моего кода.
Более того, это языковая функция для написания одноэлементного шаблона без каких-либо действий. Это особенно полезно, когда вам нужен синглтон для инкапсуляции делегатора на время существования JVM. Например, написание простой клиентской библиотеки HTTP на Scala, в которой вы можете инкапсулировать базовый делегатор на основе реализации Java и позволить потребителям вашего API жить в чистом мире.
Если вы определяете класс и объект в одном файле с тем же именем, они называются сопутствующим классом и объектом. В Scala нет static в качестве ключевого слова JAVA. Вы можете заменить static на класс-компаньон и объект в Scala.
Для получения более подробной информации, пожалуйста, проверьте класс статьи и ключевое слово объекта в программировании на Scala.
Во-первых, он обеспечивает четкое разделение статических и нестатических методов методов, а также предоставляет простой способ создания одноэлементного класса.
Он также может наследовать методы от других классов и / или признаков, что невозможно сделать с помощью статических методов Java. Его можно передать как параметр.