Scala CH10. 상속과 구성
아래의 글은 마틴 오더스키,렉스 스푼,빌 베너스 공저 / 오현석,이동욱,반영록 공역, 『Programming in Scala 3/e』,에이콘출판사(2017), CH01의 내용을 기반으로 작성하였습니다.
콤비네이터
메소드의 경우 구현이 없으면 추상 메소드다
클래스는 추상 메소드를 선언한다 ( not 정의)
파라메터 없는 메소드
빈 괄호나 아에 괄호가 없는 메소드
필드나 메소드 중 어떤 방식의로 속성을 정의하더라도 클라이언트 코드에는 영향을 끼치지 말아야 한다는 원칙 => 단일 접근 원칙
abstract class Element {
def contents: Array[String] def height: Int = contents.length def width: Int = if (height == 0) 0 else contents(0).length
}
abstract class Element1 { def contents : Array[String] val height = contents.length var width = if (height == 0) 0 else contents(0).length }
-- 필드로 할 경우 클래스 초기화 시 값이 미리 계산됨. |
스칼라에서는 파라메터 없는 메소드와 빈 괄호 메소드를 자유롭게 섞어 쓸 수 있게 한다.
메소드 오보라이드 용이
호출하는 함수가 어떠한 작업을 수행한다면 빈 괄호를 사용하라
프로퍼티에 대한 접근만 수행한다면 괄호를 생략해라
- 클래스 확장
비공개가 아닌 부모의 멤버를 모두 물려받는다
서브타입으로 만든다
서브 클래스 라고 한다
부모는 수퍼 클래스
생략하면 scala.AnyRef 상속함.
오버라이드 적용됨.
자바에 4개의 네임 스페이스 : 필드, 메소드, 타입, 패키지
스칼라에 2개의 네임 스페이스 : 값 (필드, 메소드, 패키지, 싱글톤 객체), 타입 (클래스와 트레이트 이름)
스칼라가 필드와 메소드를 동일한 네임스페이스로 취급하는 우이유는 정확히 파라미터 없는 메소드를 val로 오버라이드 하기 위해서 이다
- 파라메터 필드
class ArrayElement ( val contents: Array[String] // 동일한 필드와 파라메터를 동시에 정의하는 단축표기 ) extends Element
class Cat { var dangerous = false }
class Tiger ( override val dangerous: Boolean, private val age: Int ) extends Cat |
- 슈퍼 클래스의 생성자 호출
class LineElement(s: String) extends ArrayElement(Array(s)) { override def width = s.length override def height = 1 }
// override def hight = 1 // 컴파일 오류 |
추상 멤버를 구현한 경우에는 override 생략 가능
우연한 오버라이드는 깨지기 쉬운 기반 클래스 라고 불리는 문제의 가장 흔한 사례임.
클래스 계층에서 기반 클래스 (슈퍼 클래스) 에 추가한 멤버로 인해 클라이언트 코드가 깨지는 위험
상위에서 정의 되어 있는 것을 하위에서 override 없이 적기만 해도 컴파일 오류 남. 즉 사전에 오작동 방지 상위 메소드에서 추가하는 경우
- 다형성과 동적 바인딩
Element 타입의 변수가 하위 ArrayElement 타입의 객체를 참고 가능 : 서브 타입 다형성
val e: Element = new ArrayElement(Array("hello", "world"))
class UniformElement ( ch: Char, override val width: Int, override val height: Int ) extends Element { private val line = ch.toString * width def contents = Array.fill(height)(line) } |
변수나 표현식에 대한 메소드 호출을 동적으로 바인딩
upcating 되더라도 실제 ref class의 오버라이딩 메소드가 호출됨.
- final 멤버 선언
override 못하게 선언
class와 member에 적용 가능
- 상속과 구성 사용
상속 is a 관계
- above, beside. toString 구현
abstract class Element {
def contents: Array[String]
def width: Int = if (height == 0) 0 else contents(0).length
def height: Int = contents.length
def above(that: Element): Element = new ArrayElement(this.contents ++ that.contents)
def beside(that: Element): Element = new ArrayElement( for ( (line1, line2) <- this.contents zip that.contents ) yield line1 + line2 )
override def toString = contents mkString "\n" } |
- 팩토리 객체 정의
팩토리 객체는 다른 객체를 생성하는 메소드를 제공하는 객체이다
object Element {
private Class ArrayElement ( val contents: Array[String] ) extends Element
private class LineElement(s: String) extends Element { val contents = Array(s) override def width = s.length override def height = 1 }
private class UniformElement ( ch: Char, override val width: Int, override val height: Int ) extends Element { private val line = ch.toString * width def contents = Array.fill(height)(line) }
def elem(contents: Array[String]) : Element = new ArrayElement(contents)
def elem(chr: Char, width: Int, height: Int) : Element = new UniformElement(chr, width, height)
def elem(line: String) : Element = new LineElement(line) }
import Element.elem
abstract class Element { def contents: Array[String]
def width: Int = if (height ==0) 0 else contents(0).length
def height: Int = contents.length
def above(that: Element): Element = { val this1 = this widen that.widen val that2 = that widen this.width elem(this.contents ++ that.contents) }
def beside(that: Element): Element = { val this1 = this heighten that.height val that1 = that heighten this.height elem( for ( (line1, line2) <- this.contents zip that.contents ) yield line1 + line2 ) }
def widen(w: Int): Element = if (w <= width) this else { val left = elem(' ', (w - width) / 2, height) var right = elem(' ', w - width - left.width, height) left beside this beside right }
def heighten(h: Int): Element = if (h <= height) this else { var top = elem(' ', width, (h - height) / 2 var bot = elem(' ' , width, h - height - top.height) top above this above bot }
override def toString = contents mkString "\n" } |