Сторона FP
В Scala легко преобразовать метод в функцию. Например, если у вас есть метод:
1
|
def say(to : Person, what : String) : String = { ... } |
мы можем получить соответствующую функцию, используя символ подчеркивания:
1
|
val sayFun : (Person, String) = > String = say _ |
Кроме того, Scala поддерживает несколько списков параметров, которые иногда также называют каррированием и которые облегчают частичное применение:
1
2
3
4
5
|
// Method with multiple parameter list def connect(person 1 : Person)(person 2 : person) : Connection = { ... } // Function, created by partially applying the previous method val createConnectionWithAdam : Person = > Connection = connect( new Person( 'Adam' )) _ |
Оо сторона
В каждом классе есть конструктор. Но что на самом деле конструктор? Вы даете значения для аргументов конструктора и получаете взамен новый экземпляр класса. Так что это действительно просто функция!
1
2
3
|
class Person(name : String, age : Int) { ... } // The 'signature' of new is (String, Int) => Person val somebody = new Person( 'John' , 34 ) |
Ссылка на сайт?
Однако в Scala комбинация OO и FP терпит неудачу: вы не можете использовать две функции методов (преобразование в функцию, каррирование), упомянутые выше, с конструкторами. Оба из них не будут работать :
1
2
3
4
|
val makePerson : (String, Int) = > Person = new Person _ class Person 2 (name : String)(age : Int) { ... } val makeNewJack : Int = > Person = new Person 2 ( 'Jack' ) _ |
Вы можете обойти это, используя сопутствующие объекты и apply
(или любой другой фабричный метод, применить просто имеет более хорошие обозначения впоследствии):
1
2
3
4
5
|
object Person 2 { def apply(name : String)(age : Int) = new Person 2 (name, age) } val makeNewJack : Int = > Person = Person 2 ( 'Jack' ) _ |
Но для этого нужно повторить подпись конструктора в объекте-компаньоне, и никто не любит дублирование кода, верно? 😉
Использование регистра
Где это может быть полезно? Например в классическом заводском примере. Представьте, что у вас есть класс, который зависит от некоторых служб, а также от некоторых данных, доступных во время выполнения. Конечно, мы используем IoC, поэтому экземпляры других сервисов предоставляются нашему классу:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// This service depends on a concrete Person instance class Service 3 (service 1 : Service 1 , service 2 : Service 2 )(person : Person) { ... } / Note that the multiple parameter notation above als provides a nice // separation of the parameters that should be 'injected' - services, // and the data that can be variable. // This service depends on Service1, and wants to create it having Person // instances class Service 4 (makeService 3 : Person = > Service 3 ) { // Usage: for (person <- persons) makeService 3 (person).doSomething() } class Main { // Bootstrap: (or - no-framework DI container 😉 ) val service 1 = new Service 1 val service 2 = new Service 2 // That's the part that is illegal in Scala val makeService 3 = new Service 3 (service 1 , service 2 ) _ val service 4 = new Service 4 (makeService 1 ) ... // Today we'd have to write: val makeService3 = (person: Person) => new Service3(//service1, service2, person) } |
Это также связано с моим постом о DI и OO , а также о том, как современные структуры DI затрудняют определение сервисов, которые зависят от данных и сервисов, для которых мы хотели бы иметь несколько копий.
Примечание
При просмотре конструкторов как методов / функций (какими они на самом деле являются;)), я предполагаю Ruby-подобную нотацию:
1
|
Person. new ( 'John' , 34 ) |
было бы лучше, и добавление поддержки _ и нескольких списков параметров было бы очевидно.
Итог для поклонников TL; DR
Почему бы не рассматривать конструкторы классов как любой другой метод / функцию? Сделайте это законным:
1
2
3
4
5
|
class Person(name : String, age : Int) val makePerson = new Person _ // type: (String, Int) => Person class Person 2 (name : String)(age : Int) val makeNewJack = new Person 2 ( 'Jack' ) _ // type: Int => Person |
Ссылка: отсутствует блог OO и FP в Scala от нашего партнера по JCG Адама Варски в