abstract class는 class의 template으로, implementation은 하지 않고 어떤 variable과 method가 필요한지만 정의한다.
어떤 abstract class를 상속하는 class를 정의할 때는 abstract class에 명시된 값과 함수들을 모두 implement(작성)해야한다.
trait
trait도 abstract class와 동일한 개념이다. 하지만 abstract class는 1개의 class만 상속할 수 있는 반면, trait는 여러 class를 상속할 수 있다.
따라서 가급적이면 trait을 쓰는 것이 좋다.
abstract class를 사용해야하는 경우
1) constructor argument를 요구하는 base class를 만드는 경우 2) java에서 이용할 코드인 경우
1) 의 예시 trait Animal(name: String) //compile error
case class
scala에는 case class라는 재미있는 class가 있다. switch case 문처럼 scala 에서는 match case문이 존재한다. 특이한 것은 match case와 case class문을 조합하면, object의 class에 대해서도 switch case를 할 수 있다.
예를 들어보자. 어떤 수학 수식은 숫자(number)와 연산자(operator)로 구성된다. 숫자와 연산자를 포함하는 Expression이라는 abstract class(trait)을 정의하면, 수식을 Expression의 List로 나타낼 수 있다.
triat Expression
case class Number(val: Int) extends Expression {...}
case class Operator(name: String) extends Expression {...}
// Expression을 상속하는 class Number, class Operator 정의
object O {
def expr(x : Base) = x match {
case Number(val: Int) => println("x is in class Number")
case Operator(name: String) => println("x is in class Operator")
}
// x가 Number의 instance 이면 "x is in class Name!"를 출력하고
// x가 Operator의 instance 이면 "x is in class Operator!"를 출력한다.
}
Singleton object
Singleton은 class의 instance가 하나만 존재하는 object이다. class의 instance가 하나만 존재해야하는 경우가 있다. 이 경우에는 class 대신 object를 이용한다.
class Person {...} 대신
object Person {...}
그리고 singleton object는 다음과 같은 특징을 갖는다. 1) 유일하다. 2) 생성자를 정의하지 않는다. 3) new를 이용해서 생성하지 않는다.
Companion Object
class와 이름이 같은 object이다. static 변수와 method를 정의할 때 companion object를 이용한다.
class Pizza() {...}
Object Pizza {
val size = 26
def alertAllergy = println("It contains cheese")
}
primary constructor scala는 java와 달리 class 이름 옆에 parameter를 명시함으로써 primary constructor를 정의한다.
auxilary constructor 추가적인 constructor는 this를 이용해서 아래와 같이 정의한다.
class Person(first_name:String, last_name:String){
var age = -1
def this(first_name, last_name:String, age:Int) {
this(first_name, last_name)this.age = age
}
}
private constructor : private 생성자
class Person private(name: String ){ ... }
default value : 기본값 지정
class Person private(name: String = "hello" ){ ... }
extends를 이용할 때 어떤 생성자를 이용할지 명시할 수 있다.
class Employee(name:String) extends Person (name: String){ ... }
instance 생성(new)
new를 통해 생성한다.
parameter가 없는 생성자인 경우, ()를 생략할 수 있다.
function의 경우에도 parameter가 없는 경우 ()를 생략할 수 있다.
class AA {
var vv = 0
def kk = println("without ()")
def kk2() = println("with ()")
}
object O {
def main(args: Array[String]):Unit = {
val a = new AA
val b = new AA()
println("a", a)
println("b", b)
//실행 결과
//(a,AA@7112f2df)
//(b,AA@f8ec7ed)
a.kk
b.kk() // compile error
실행 결과
//without ()
a.kk2
b.kk2()
실행 결과
//with ()
//with ()
}
}
Reactive Programming과 Functional Reactive Programming 의 개념을 알아보자
Reactive Programming
Wikipedia는 역시 너무 어렵다.
a declarative programming paradigm concerned with data streams and the propagation of change.
// 데이터의 순서와 변경과 관련된 선언적 프로그래밍 패러다임
더 직관적인 뜻을 찾아보자.
Reactive programming is programming with asynchronous data streams.
// 비동기 데이터 흐름을 다루는 프로그래밍
// 출처: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
글만 보면 막연하니, 그림을 보자.
블로그에 글을 작성하는 상황을 예를 들어서 생각해보자,
Data stream이란 시간의 흐름에 따라 진행되는 이벤트의 sequence를 말한다.
조금 쉽게 생각하면, 연속된 데이터의 처리/operation라고 할 수 있다.
블로그에 글을 작성하는 경우에는, 위의 순서로 이벤트가 발생한다 / 데이터가 처리된다.
reactive programming은 비동기 이벤트 흐름을 다루며, 이름 그대로 빠르게 반응하는 것을 목표로 한다. 빠르게 반응하기 위해서는 이벤트가 발생하는지 관찰하고(observe) 값이 변할 때마다 새로 연산을 수행해아한다.
이렇게, 객체 A에 변화가 생기면 객체 A를 관찰하는 observer들에게 변화를 통지하는 패턴을 observation design pattern이라고 한다. 비동기 이벤트를 처리하는 reactive programming은 observation design pattern을 기본으로 한다.
이벤트 하나가 완료되면, value / error / complete signal 중 하나가 발생한다. observer는 발생값(value/error/complete signal)에 따라 다른 함수(handler)를 실행한다.
이벤트의 처리 신호를 듣는다(listen)고도 표현하며 처리 신호를 observer에게 보내는 것을 subscribe라고도 한다.
Functional Reactive Programming
Functional Reactive Programming은 Reactive Programming을functional programming을 이용해서 구현한 것이다.
functional programming이란, 수학적 의미의 함수의 역할이 강조된 프로그래밍 기법이다.
수학적 의미에서의 함수란, input을 넣으면 output이 나오는 box로 생각할 수 있다.
예를 들면, imperative programming에서는 흔히, 아래처럼 함수를 작성하지만,
def add(a:Int):Int = a + 3
functional programming에서는 state를 갖는 것을 피하고, 숨겨진 input과 output을 없도록 하기 위해서 아래처럼 작성한다.
def add(a:Int, b:Int) = a+b
여기서 숨겨진 input과 숨겨진 output을 각각 side-cause, side-effect라고 한다.
이것들이 많아지면 코드를 변경할 때 예상하지 못한 결과가 나올 수 있고,
코드를 변경할 때 모든 함수의 내부를 확인하면서 디버깅을 해야하는 어려움이 있다.
functional reactive programming은 결국 side effect를 줄이면서 reactive programming을 구현하는 방법인 것이다!
구체적인 구현 코드는 다음 글에서 알아보자
4 Reactive principles
Reactive programming은 4가지의 principle을 갖는다.
1) responsive : 빠르게 반응한다. reactive programming의 방법이기도 하다. 2) resilient : 어떤 상황에서도 responsive하게 동작하도록 한다. 3) scalable : load에 따라 responsive할 수 있도록 시스템을 업그레이드할 수 있다. 4) message driven : reactive programming을 구현하는 방법이다. event-driven, actor-based, event-driven + actor-based가 있다. event-driven : observer가 event를 관찰한다. actor-based : message가 actor에게 직접 전달된다.