Классы и объекты в Scala
Если вы программировали на языке Java, то многие вещи на Scala относительно ООП будут вам знакомы. Для объявления класса используется ключевое слово class, новый экземпляр объявляется через new.
Рассмотрим пример использования класса в Scala:
class Foo(x: Int) { def bar(y: Int) = x + y } val foo = new Foo(1) // foo: Foo = Foo@69007238 foo.bar(1) // res4: Int = 2
А теперь перед нами аналогичный код, но уже на Java:
class Foo { private int x_; Foo(int x) { _x = x; } public int bar(int y) { return x + y; } } Foo foo = new Foo(1) int result = foo.bar(1) // result теперь равен 2
Обратите внимание, что в Scala public указывать не обязательно, и аргументы конструктора доступны во всем классе, а локальное приватное поле создавать тоже не обязательно. Вдобавок к этому, в Scala можно сразу объявить объект без создания класса, используя ключевое слово object. В результате реализуется паттерн Singleton.
object Singleton(field: String) { def squareMe(x: Int) = x*x } Singleton.squareMe(2) // res5: Int = 4
А вот аналогичный код на Java будет более объёмным:
public class Singleton { private static Singleton instance = null; protected Singleton() { // Exists only to defeat instantiation. } public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } public int squareMe(int x) { return x*x; } } int a = Singleton.getInstance().squareMe(2) // a теперь равен 4
В нашем примере мы пометили конструктор как protected, дабы исключить возможность его вызова извне, то есть обращение к объекту будет выполняться с помощью метода
Но вернёмся к конструкторам и вспомним, что в случае использования любого объекта к некоторым аргументам по дефолту вызывается метод apply. Воспользуемся этим и напишем класс с несколькими статическими методами, конструкторами, неизменяемыми и изменяемыми полями в идиоматичном для Scala стиле, а потом продублируем тот же код, но уже на Java.
Итак, вариант Scala:
object MyUselessClass { def staticMethod(x: Int) = x + 5 def apply(immutableField: Int): MyUselessClass = new MyUselessClass(immutableField, 2) def apply(immutableField: Int, mutableField: Int): MyUselessClass = new MyUselessClass(immutableField, mutableField) def apply(immutableField: Int, mutableField: Int, privateField: Int): MyUselessClass = new MyUselessClass(immutableField, mutableField, privateField) } class MyUselessClass(val immutableField: Int, var mutableField: Int, privateField: Int = 8 /*значение по умолчанию*/) { def instanceMethod() = { val sumOfFields = immutableField + mutableField + privateField MyUselessClass.staticMethod(sumOfFields) } } // 1-й конструктор, обратите внимание на отсутствие 'new', // ведь на самом деле это вызов метода 'apply' val myUselessObject = MyUselessClass(1) // как и в предыдущем варианте val myAnotherUselessObject = MyUselessClass.apply(1) // 3-й конструктор val myThirdUselessObject = MyUselessClass(1, 2, 3) // Вызываем метод myUselessObject.instanceMethod() // res6: Int = 16 // Поля доступны так же, как методы myUselessObject.mutableField // res7: Int = 2 myUselessObject.immutableField // res8: Int = 1 myUselessObject.mutableField = 9 myUselessObject.mutableField // res9: Int = 9 // Вызываем статический метод MyUselessClass.staticMethod(3) // res10: Int = 8
А теперь смотрим Java-вариант:
public class MyUselessClass { private int immutableField_; private int mutableField_; private int privateField_ = 8; MyUselessClass(int immutableField) { immutableField_ = immutableField; mutableField_ = 2; } MyUselessClass(int immutableField, int mutableField) { immutableField_ = immutableField; mutableField_ = mutableField; } MyUselessClass(int immutableField, int immutableField, int privateField) { immutableField_ = immutableField; mutableField_ = mutableField; privateField_ = privateField; } int getImmutableField() { return immutableField; } int getMutableField() { return mutableField; } void setMutableField(int newValue) { mutableField = newValue; } public static int staticMethod(int x) { return x + 5; } public int instanceMethod() { int sumOfFields = immutableField + mutableField + privateField; return staticMethod(sumOfFields); } } // 1-й конструктор MyUselessClass myUselessObject = new MyUselessClass(1) // 3-й конструктор MyUselessClass myAnotherUselessObject = new MyUselessClass(1, 2, 3) // Вызываем метод myUselessObject.instanceMethod() // возвратит 16 // Поля доступны так же, как методы myUselessObject.getMutableField // возвратит 2 myUselessObject.getImmutableField // возвратит 1 myUselessObject.setMutableField(9) myUselessObject.getMmutableField // возвратит 9 // Вызываем статический метод MyUselessClass.staticMethod(3) // возвратит 8
Материал подготовлен на основании статьи "Быстрый старт со Scala".