Created
July 4, 2018 00:42
-
-
Save mrbkdad/5cb32512bec67b603aeee231cc3aa880 to your computer and use it in GitHub Desktop.
learning scala chapter 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 5 클래스\n", | |
"- 클래스의 필드는 자동으로 게터와 세터를 만든다\n", | |
"- 클래스의 클라이언트를 바꾸지 않고 필드를 맞춤 게터/세터로 교체 할 수 있다.(단일 접근 원칙)\n", | |
" - 단일접근원칙 : 모듈이 제공하는 모드 서비스는 단일한 표기법으로 접근 가능해야 한다. 저장소로 구현했는지 계산으로 구현했는지를 누설해서는 안된다(Bertrand Meyer)\n", | |
"- 자바빈 getXxx/SetXxx 메소드를 생성하려면 @Beanproperty 표기법 사용\n", | |
"- 모든 클래스는 클래스 정의와 \"뒤썩인\" 기본 생성자를 갖고 있다.\n", | |
"- 기본 생성자의 인자는 클래스 필드가 된다.\n", | |
"- 기본 생성자는 클래스 바디의 모든 문을 실행한다.\n", | |
"- 보조 생성자는 선택적이다. 보조 생성자는 this라고 부른다." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 간단한 클래스와 인자 없는 메소드\n", | |
"- 모든 클래스는 public\n", | |
"- 인자 없는 메소드 정의시 조회성은 () 없이 정의 하고 상태를 변경하는 메소드는 ()와 같이 정의한다" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Counter{\n", | |
" private var value = 0\n", | |
" def increment() { value += 1 }\n", | |
" def current() = value\n", | |
" def currentValue = value\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Counter@5d10ab46" | |
] | |
}, | |
"execution_count": 2, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val myCounter = new Counter\n", | |
"myCounter" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"1\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"1" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"myCounter.increment()\n", | |
"println(myCounter.current)\n", | |
"myCounter.currentValue" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:21: error: Int does not take parameters\n", | |
" myCounter.currentValue()\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"myCounter.currentValue()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 게터와 세터\n", | |
"- 자바에서는 private 필드와 getter, setter를 작성하여 프러퍼티를 정의한다.\n", | |
"<pre>\n", | |
"public class Person{\n", | |
" private int age;\n", | |
" public int getAge() {\n", | |
" return age;\n", | |
" }\n", | |
" public void setAge(int age) {\n", | |
" this.age = age;\n", | |
" }\n", | |
"}\n", | |
"</pre>\n", | |
"- 스칼랑서는 모든 public 필드에 대해 게터와 세터 메소드를 제공한다.\n", | |
" - var\n", | |
" - JVM용으로 클래스 생성시 내부적으로 처리된다.\n", | |
" - getter : field_name()\n", | |
" - setter : field_name_=(field type parameter)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person{\n", | |
" var age = 0\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"* Person 클래스를 컴파일후 javap로 바이트 코드를 확인하면 아래와 같다.\n", | |
"\n", | |
"<pre>\n", | |
"$ scalac Person.scala\n", | |
"$ javap -private Person\n", | |
"Compiled from \"Person.scala\"\n", | |
"\n", | |
"public class Person extends java.lang.Object implements scala.ScalaObject{\n", | |
" private int age;\n", | |
" public int age();\n", | |
" public void age_$eq(int);\n", | |
" public Person();\n", | |
"}\n", | |
"</pre>\n", | |
"\n", | |
"* 컴파일러는 age와 age_$eq 메소드를 생성함(JVM에서는 메소드 이름에 = 을 허용하지 않음)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 게터와 세터 재정의\n", | |
"- 단일 접근 원칙" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person{\n", | |
" private var privateAge = 0\n", | |
" \n", | |
" def age = privateAge\n", | |
" def age_=(newValue: Int){\n", | |
" if(newValue > privateAge) privateAge = newValue\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"30" | |
] | |
}, | |
"execution_count": 7, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val fred = new Person\n", | |
"fred.age = 30\n", | |
"fred.age = 21\n", | |
"fred.age" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 게터만 있는 프로퍼티\n", | |
"- val : scala는 final 필드와 게터를 만들고 세터는 만들지 않는다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Message{\n", | |
" val timeStamp = new java.util.Date\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 프로퍼티 구현\n", | |
"1. var foo : 스칼라가 게터와 세터 합성\n", | |
"2. val foo : 스칼라가 게터를 합성\n", | |
"3. 메소드 foo, foo_= 직접 정의\n", | |
"4. 메소드 foo 직접 정의\n", | |
"- 스칼라에서는 쓰기 전용 프로퍼티는 불가능(세터만 있고 게터가 없는 프로퍼티)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 오브젝트 - 비공개 필드\n", | |
"- 메소드는 해당 클래스의 모든 오브젝트의 private field에 접근 가능(자바, C++)\n", | |
"- private[this] : 현재 오브젝트의 필드만 접근 가능하게 제한한다.\n", | |
" - 게터와 세터가 생성 되지 않음" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Counter{\n", | |
" private var value = 0\n", | |
" def increment() { value += 1 }\n", | |
" def isLess(other: Counter) = value < other.value\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"true" | |
] | |
}, | |
"execution_count": 10, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val cnt1 = new Counter\n", | |
"val cnt2 = new Counter\n", | |
"cnt2.increment()\n", | |
"cnt1.isLess(cnt2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:17: error: value value is not a member of Counter\n", | |
" def isLess(other: Counter) = value < other.value\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"class Counter{\n", | |
" private[this] var value = 0\n", | |
" def increment() { value += 1 }\n", | |
" def isLess(other: Counter) = value < other.value\n", | |
"}\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 빈 프로퍼티\n", | |
"- @BeanProperty\n", | |
"<pre>\n", | |
"import scala.beans.BeanProperty //scala.reflect.BeanProperty\n", | |
"\n", | |
"class Person{\n", | |
" @BeanProperty\n", | |
" var name:String = _\n", | |
"}\n", | |
"</pre>\n", | |
"\n", | |
"- default\n", | |
" 1. name: String\n", | |
" 2. name_=(newValue: String): Unit (var)\n", | |
"- @BeanProperty\n", | |
" 3. getName(): String\n", | |
" 4. setName(newVlaue: String): Unit (var)\n", | |
"- private[this] : X" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person{\n", | |
" import scala.beans.BeanProperty\n", | |
" @BeanProperty\n", | |
" var name:String = _\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"name" | |
] | |
}, | |
"execution_count": 13, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val p = new Person\n", | |
"p.setName(\"name\")\n", | |
"p.getName" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 보조 생성자\n", | |
"- 여러 생성자를 만들수 있음\n", | |
"- 스칼라는 중요생성자 하나와 여러개의 보조 생성자를 가질수 있음\n", | |
"- 보조 생성자\n", | |
" - this (자바나 c++ 에서는 생성자는 클래스와 같은 이름을 가짐)\n", | |
" - 보조생성자는 기본 생성자 호출로 시작 해야함" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person{\n", | |
" private var name = \"\"\n", | |
" private var age = 0\n", | |
" \n", | |
" def this(name: String){\n", | |
" this() // 기본 생성자\n", | |
" this.name = name\n", | |
" }\n", | |
" \n", | |
" def this(name: String, age: Int){\n", | |
" this(name)\n", | |
" this.age = age\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"val p1 = new Person\n", | |
"val p2 = new Person(\"Fred\")\n", | |
"val p3 = new Person(\"Fred\",42)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 기본 생성자\n", | |
"- this 메소드로 정의하지 않음\n", | |
"- 클래서 정의와 뒤썩인다.\n", | |
"- 기본 생성자 인자들은 클래스와 함께 정의 된다 : class name(parameters){...}\n", | |
" - 클래스 생성시 초기화 된다.\n", | |
"- 기본 생성자는 클래스 정의에 있는 모든 문을 실행한다.\n", | |
"- 클래스 이름 뒤에 인자가 없으면, 클래스는 인자가 없는 기본 생성자를 가지게 된다.\n", | |
"- 기본 생성자에서 디폴트 인자를 사용 할 수 있다.\n", | |
"- 기본 생성자의 인자를 val/var 없이 정의 하면 private[this] val 필드로 정의 된다.\n", | |
"- private 혹은 @BeanProperty 정의 가능\n", | |
"- 기본 생성자를 비공개로 만들려면 class name private(...){...} 처럼 사용한다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person(var name: String = null, var age: Int = 0){ printf(\"name:%s, age:%s\\n\",name,age)}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"name:null, age:0\n", | |
"name:Fred, age:0\n", | |
"name:Fred, age:42\n" | |
] | |
} | |
], | |
"source": [ | |
"val p1 = new Person\n", | |
"val p2 = new Person(\"Fred\")\n", | |
"val p3 = new Person(\"Fred\",age=42)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Person(name: String,age: Int){\n", | |
" def desc = name + \" is \" + age + \" years old\"\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Fred is 42 years old" | |
] | |
}, | |
"execution_count": 19, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val p4 = new Person(\"Fred\",age=42)\n", | |
"p4.desc" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Fred" | |
] | |
}, | |
"execution_count": 20, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"p3.name" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:21: error: value name is not a member of Person\n", | |
" p4.name\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 21, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"p4.name" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:15: error: value age is not a member of Person\n", | |
" def compare(oth:Person) = oth.age > age\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 22, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"class Person(name: String,age: Int){\n", | |
" def compare(oth:Person) = oth.age > age\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 중첩 클래스\n", | |
"- 함수 중첩 가능\n", | |
"- 클래스 중첩 가능\n", | |
"- 중첩 클래스 생성시 new instance_name.class_name ( 자바에서는 instance_name.new class_name() )" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Network {\n", | |
" import scala.collection.mutable.ArrayBuffer\n", | |
" class Member(val name: String){\n", | |
" val contacts = new ArrayBuffer[Member]\n", | |
" println(name + \"'s contacts : \" + contacts)\n", | |
" }\n", | |
" \n", | |
" private val members = new ArrayBuffer[Member]\n", | |
" \n", | |
" def join(name: String) = {\n", | |
" val m = new Member(name)\n", | |
" members += m\n", | |
" m\n", | |
" }\n", | |
" \n", | |
" def memberList = members.map(_.name).mkString(\",\")\n", | |
"}\n", | |
"\n", | |
"val chatter = new Network\n", | |
"val myFace = new Network" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 24, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Fred's contacts : ArrayBuffer()\n", | |
"Wilma's contacts : ArrayBuffer()\n", | |
"Barney's contacts : ArrayBuffer()\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:25: error: type mismatch;\n", | |
" found : chatter.Member\n", | |
" required: chatter.Member\n", | |
" fred.contacts += wilma\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 24, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"val fred = chatter.join(\"Fred\")\n", | |
"val wilma = chatter.join(\"Wilma\")\n", | |
"val barney = myFace.join(\"Barney\")\n", | |
"fred.contacts += wilma" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:27: error: type mismatch;\n", | |
" found : myFace.Member\n", | |
" required: chatter.Member\n", | |
" fred.contacts += barney\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 25, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"fred.contacts += barney" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 위와 같은 문제의 해결책\n", | |
"- company object 이용\n", | |
"- 타입 프로젝션 : Network#Member" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 26, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Fred's contacts : ArrayBuffer()\n", | |
"Wilma's contacts : ArrayBuffer()\n", | |
"Barney's contacts : ArrayBuffer()\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:25: error: type mismatch;\n", | |
" found : chatter.Member\n", | |
" required: chatter.Member\n", | |
" fred.contacts += wilma\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 26, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"object Network{\n", | |
" import scala.collection.mutable.ArrayBuffer\n", | |
"\n", | |
" class Member(val name: String){\n", | |
" val contacts = new ArrayBuffer[Member]\n", | |
" println(name + \"'s contacts : \" + contacts)\n", | |
" }\n", | |
"}\n", | |
"class Network {\n", | |
" import scala.collection.mutable.ArrayBuffer\n", | |
" \n", | |
" private val members = new ArrayBuffer[Network.Member]\n", | |
" \n", | |
" def join(name: String) = {\n", | |
" val m = new Network.Member(name)\n", | |
" members += m\n", | |
" m\n", | |
" }\n", | |
" \n", | |
" def memberList = members.map(_.name).mkString(\",\")\n", | |
"}\n", | |
"val fred = chatter.join(\"Fred\")\n", | |
"val wilma = chatter.join(\"Wilma\")\n", | |
"val barney = myFace.join(\"Barney\")\n", | |
"fred.contacts += wilma\n", | |
"fred.contacts += barney" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 27, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Fred's contacts : ArrayBuffer()\n", | |
"Wilma's contacts : ArrayBuffer()\n", | |
"Barney's contacts : ArrayBuffer()\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"Name: Compile Error\n", | |
"Message: <console>:25: error: type mismatch;\n", | |
" found : chatter.Member\n", | |
" required: chatter.Member\n", | |
" fred.contacts += wilma\n", | |
" ^\n", | |
"StackTrace: " | |
] | |
}, | |
"execution_count": 27, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"class Network {\n", | |
" import scala.collection.mutable.ArrayBuffer\n", | |
" class Member(val name: String){\n", | |
" val contacts = new ArrayBuffer[Network#Member]\n", | |
" println(name + \"'s contacts : \" + contacts)\n", | |
" }\n", | |
" \n", | |
" private val members = new ArrayBuffer[Member]\n", | |
" \n", | |
" def join(name: String) = {\n", | |
" val m = new Member(name)\n", | |
" members += m\n", | |
" m\n", | |
" }\n", | |
" \n", | |
" def memberList = members.map(_.name).mkString(\",\")\n", | |
"}\n", | |
"val fred = chatter.join(\"Fred\")\n", | |
"val wilma = chatter.join(\"Wilma\")\n", | |
"val barney = myFace.join(\"Barney\")\n", | |
"fred.contacts += wilma\n", | |
"fred.contacts += barney" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Apache Toree - Scala", | |
"language": "scala", | |
"name": "apache_toree_scala" | |
}, | |
"language_info": { | |
"file_extension": ".scala", | |
"name": "scala", | |
"version": "2.11.8" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment