Есть ли случай, когда нужен сопутствующий объект (синглтон) для класса? Зачем мне, скажем, создавать класс, 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. Его можно передать как параметр.