169
3
기초를 튼튼히
scala
>
val name
=
"
Dean Wampler
"
name
:
String
=
"
Dean Wampler
"
scala
>
s
"
123
\
n
$
name
\
n456
"
res0
:
String
=
123
Dean Wampler
456
scala
>
raw
"
123
\
n
$
name
\
n456
"
res1
:
String
=
123
\
nDean Wampler
\
n456
원한다면 자신만의 문자열 인터폴레이션을 정의할 수도 있다. 하지만 그렇게 하기 위해서는
implicits
에 대해 더 배워야 한다.
5
.
3
.
1
절 ‘자신만의 문자열 인터폴레이션 만들기’에서 자세한
내용을 있다.
3.14
트레이트: 스칼라 인터페이스와 혼합
지금까지 상당히 많은 내용을 설명했지만, 아직 자바의 인터페이스
interface
동등한 추상화를
의하는 방법이나 클래스를 상속하는 방법 객체지향 언어의 기본 특성에 대해서는 하나도
명하지 않았다.
이런 내용을 제외한 이유는 스칼라를 통한 함수형 프로그래밍이 얼마나 강력한 능력을 가지는지
강조하기 위해서였다. 하지만 이제 중요한 주제를 다루기 적절한 시점에 도달했다.
필자는 앞에서 추상화
abstractions
같은 모호한 용어를 사용했다. 예제 일부는
abstract
클래
스를 이미 ‘부모’ 클래스로 사용했다. 하지만 여러분이 비슷한 구성 요소를 다른 언어에서 이미
봤을 것이라 가정하고, 내용을 자세히 살펴보지는 않았다.
자바에는
interface
있다. 자바
8
사용하지 않는 한, 여러분은 안에 메서드를 선언
declare
있지만 정의
define
수는 없다. 또한
static
변수
10
내포된 타입을 정의할 있다.
10
역주_ 다만 자바 인터페이스 안의 변수는 별도로 지정하지 않더라도 무조건 상수다(즉,
public
static
final
이 암시적으로 붙는
다고 생각하면 된다).
170
1
스칼라와의 만남
스칼라는 인터페이스를 트레이트
trait
바꿨다. 이에 대해서는
9
장에서 자세히 다룰 것이다.
금은 트레이트메서드를 선언하면서 원하면 정의까지 할 있는 인터페이스’생각하라.
또한 트레이트에 인스턴스 필드를 선언하고 원한다면 정의까지 할 수 있다 (정적 필드만 가능한
자바 인터페이스와는 다르다 ). 또한 전의 열거값 예제에서 본 것처럼 원한다면 타입값을
의할 수도 있다.
이는 클래스 안에서만 메서드와 필드를 정의할 있는 자바 객체 모델의 여러 한계를 확장한다.
트레이트를 사용하면 자바
8
이전의 자바에서는 불가능했던 동작의 진정한 조합, 즉 혼합
mixin
가능해진다.
지금부터 모든 기업 자바 개발자가 직면하게 되는 문제인, 로그를 남기는 기능을 혼합하는 것
살펴보겠다. 먼저 서비스부터 정의하자.
//
src
/
main
/
scala
/
progscala2
/
rounding
/
traits
.
sc
class ServiceImportante
(
name
:
String
)
{
def work
(
i
:
Int
):
Int
=
{
println
(
s
"
ServiceImportante
:
Doing important work
!
$
i
")
i
+
1
}
}
val service1
=
new ServiceImportante
("
uno
")
(
1 to 3
)
foreach
(
i
=
>
println
(
s
"
Result
:
${
service1
.
work
(
i
)}"))
서비스에 작업을 요청하면 다음 출력을 얻는다.
ServiceImportante
:
Doing important work
!
1
Result
:
2
ServiceImportante
:
Doing important work
!
2
Result
:
3
ServiceImportante
:
Doing important work
!
3
Result
:
4
표준 로깅 라이브러리를 혼합하자. 단순하게 그냥
println
사용할 것이다.
171
3
기초를 튼튼히
여기 가지 트레이트가 있다. 하나는 아무런 구체적 멤버가 없는 추상화를 정의하며,
나는 추상화를 구현’해서 표준 출력에 로그를 남긴다.
trait Logging
{
def info
(
message
:
String
):
Unit
def warning
(
message
:
String
):
Unit
def error
(
message
:
String
):
Unit
}
trait StdoutLogging extends Logging
{
def info
(
message
:
String
)
=
println
(
s
"
INFO
:
$
message
")
def warning
(
message
:
String
)
=
println
(
s
"
WARNING
:
$
message
")
def error
(
message
:
String
)
=
println
(
s
"
ERROR
:
$
message
")
}
Logging
은 자바 인터페이스와 정확히 같다. 심지어
JVM
바이트 코드에서는 구현까지도 인터
페이스와 동일하다.
마지막으로 로그 기능을 혼합’하는 서비스를 선언하자.
val service2
=
new ServiceImportante
("
dos
")
with StdoutLogging
{
override def work
(
i
:
Int
):
Int
=
{
info
(
s
"
Starting work
:
i
=
$
i
")
val result
=
super
.
work
(
i
)
info
(
s
"
Ending work
:
i
=
$
i
,
result
=
$
result
")
result
}
}
(
1 to 3
)
foreach
(
i
=
>
println
(
s
"
Result
:
${
service2
.
work
(
i
)}"))
이제
work
들어갈 때와 나올 로그를 남기게 된다.
INFO
:
Starting work
:
i
=
1
ServiceImportante
:
Doing important work
!
1
INFO
:
Ending work
:
i
=
1
,
result
=
2
Result
:
2
INFO
:
Starting work
:
i
=
2
172
1
스칼라와의 만남
ServiceImportante
:
Doing important work
!
2
INFO
:
Ending work
:
i
=
2
,
result
=
3
Result
:
3
INFO
:
Starting work
:
i
=
3
ServiceImportante
:
Doing important work
!
3
INFO
:
Ending work
:
i
=
3
,
result
=
4
Result
:
4
트레이트를 혼합하기 위해
with
라는 키워드를 사용한다. 원하는 만큼 얼마든지 트레이트를
합할 수 있다. 일부 트레이트는 기존 클래스의 동작을 전혀 바꾸지 않으면서도 새롭고 유용하며
독립적인 메서드를 추가해준다.
이 예제에서 우리는 실제로 로그 기능을 주입하기 위해
work
의 동작을 변경했다. 하지만 고객
과의 계약’, 외부 동작
11
변경하지 않았다.
만약
ServiceImportante
with
StdoutLogging
인스턴스가 많이 필요하다면, 클래스를
언할 수도 있다.
class LoggedServiceImportante
(
name
:
String
)
extends ServiceImportante
(
name
)
with StdoutLogging
{...}
name
인자를 부모 클래스인
ServiceImportante
어떻게 넘기는지 주의 깊게 살펴보라. 인스
턴스를 만들 때는
new
LoggedServiceImportante
("
tres
")
라고 하면 예상대로 동작한다.
하지만 인스턴스가 하나만 필요하다면, 앞에서
service2
를 정의할 때처럼
StdoutLogging
혼합할 있다.
로그 기능 확장을 사용하려면
work
메서드를 오버라이드해야 한다. 스칼라에서는 부모 클래스
에서 정의한 구체적 메서드를 오버라이드할 때
override
키워드를 명시해야 한다. 자바나 다
언어에서처럼
super
.
work
사용해서 부모 클래스에 있는
work
메서드를 사용했다는 점을
확인하라.
트레이트와 객체 합성에 대해서는 논의할 내용이 훨씬 많다. 나중에 이에 대해 알게 것이다.
11
주_ 추가적인
I
/
O
세상코드의 상호 작용을 변경하므로, 이는 엄밀히 말하면 참이 아니다.

Get 프로그래밍 스칼라: 실용적인 스칼라 활용법을 익히는 가장 확실한 실전 바이블 (2.11.x 버전 기반) now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.