Skip to content

Instantly share code, notes, and snippets.

@mrbkdad
Created July 4, 2018 00:42
Show Gist options
  • Save mrbkdad/5cb32512bec67b603aeee231cc3aa880 to your computer and use it in GitHub Desktop.
Save mrbkdad/5cb32512bec67b603aeee231cc3aa880 to your computer and use it in GitHub Desktop.
learning scala chapter 5
Display the source blob
Display the rendered blob
Raw
{
"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