В чем причина наличия сопутствующих объектов в Scala?
-
03-07-2019 - |
Вопрос
Есть ли случай, когда для объекта нужен сопутствующий объект (singleton)? Зачем мне создавать класс, скажем, Foo
, а также создавать для него объект-компаньон?
Решение
Сопутствующий объект в основном предоставляет место, где можно поместить "статический". методы. Кроме того, объект-компаньон или модуль-компаньон имеет полный доступ к членам класса, включая частные.
Сопутствующие объекты отлично подходят для инкапсуляции таких вещей, как фабричные методы. Вместо того, чтобы иметь, например, Foo
и FooFactory
повсюду, вы можете иметь класс с сопутствующим объектом, принимающим на себя фабричные обязанности.
Другие советы
Сопутствующие объекты полезны для хранения состояния и методов, которые являются общими для всех экземпляров класса , но они не используют статические методы или поля. Они используют обычные виртуальные методы, которые могут быть переопределены через наследование. Скала действительно не имеет ничего статичного. Есть много способов использовать это, но вот простой пример.
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, потому что он не выглядит плохо: как создание чего-то абстрактного. Дайте этим именам реальный смысл. Подумайте об использовании неизменяемых, метода less, классов case и закройте абстрактный базовый класс. Р>
В дополнение к тому, что сказал Саэм в его ответ , компилятор Scala также ищет неявные преобразования типов в соответствующих сопутствующих объектах (источника или цели), поэтому преобразования не нужно импортировать.
О причине одиночных объектов в целом Программирование в Scala говорит:
Как упоминалось в главе 1, один из способов, с помощью которого Scala является более объектно-ориентированным, чем Java, состоит в том, что классы в Scala не могут иметь статических членов. Вместо этого в Scala есть одноэлементные объекты (стр. 65).
Я всегда вижу сопутствующие объекты как мост для написания как функционального, так и объектно-ориентированного кода в Scala. Много раз нам просто нужны чистые функции, которые принимают некоторый ввод и обеспечивают результат обработки. Помещение этих соответствующих функций в объект-компаньон облегчает поиск и использование, как для меня, так и для одного здания поверх моего кода. Р>
Кроме того, это функция, предоставляемая языком, для написания одноэлементного шаблона без каких-либо действий. Это особенно полезно, когда вам нужен синглтон для инкапсуляции делегатора на всю жизнь JVM. Например, написание простой клиентской библиотеки HTTP в Scala, в которой вы можете инкапсулировать базовый делегатор, основанный на реализации Java, и позволить потребителям вашего API жить в чистом мире.
Если вы определяете класс и объект в одном файле с одинаковым именем, они называются сопутствующим классом и объектом. В Scala отсутствует статическое ключевое слово JAVA. Вы можете использовать его в качестве замены статического класса и объекта-компаньона в Scala.
Для более подробной информации, пожалуйста, проверьте статью ключевое слово класса и объекта в программировании scala р>
Во-первых, он обеспечивает четкое разделение статических и нестатических методов. Также предоставляется простой способ создания одноэлементного класса.
Он также может наследовать методы от других классов и / или признаков, что невозможно сделать статическими методами Java. И может быть передано в качестве параметра.