이번 주 프로그래밍 과제가 2개가 나갔었다. 하나는 계산기 프로그램을 짜는 것으로 필수적으로 해야 하는 것이고, 다른 하나는 호텔 예약 프로그램을 짜는 것으로 선택적으로 해도 되는 것이었다. 시간에 여유가 생겨서라고 했지만 사실 자야 할 3시간을 안 자고 여기에 매달렸다 선택 과제를 해냈는데, 자고 일어나서 이 두 과제에 대해 코드 개선을 진행하며 - Java로 짤 때 썼을 것 같은 코드들을 쓰고 나서 몇개 목격해서 이번에 Kotlin에서 쓸 것 같은 스타일로 몇몇 부분들을 다듬었다 - 새로 알게 된 부분들을 어제에 이어서 적어보고자 한다.

배웠던/느꼈던 점

settergetter메서드를 명시적으로 쓰지 않아도 된다 + 생성자를 간략화할 수 있다

작년에 Java를 공부하면서 코드를 몇몇 만들어 보았는데,

public class StudentScore {
	private String name;
	private int scoreKorean;
	private int scoreMath;
	private int scoreEnglish;
}

-와 같은 학생 성적 class가 있다고 하자. 이름(문자열), 국어 성적(정수), 수학 성적(정수), 영어 성적(정수) 필드가 있다. private 접근 제어자(access modifier)를 두어 객체 외부에서 임의로 필드에 직접 접근하는 - 읽고 쓰는 - 걸 막았다. 외부에서 접근하고 수정할 수 있게 만들기 위해선 getter(획득자) 메서드와 setter(설정자) 메서드를 두어 외부에서의 접근 권한을 설정할 수 있다. 가령:

public class StudentScore {
	private String name;
	private int scoreKorean;
	private int scoreMath;
	private int scoreEnglish;
 
	// constructor
	public StudentScore(String name, int scoreKorean, int scoreMath, int scoreEnglish) {
		this.name = name;
		this.scoreKorean = scoreKorean;
		this.scoreMath = scoreMath;
		this.scoreEnglish = scoreEnglish;
	}
 
	// setter 메서드
	public void setName(String name){ this.name = name; }
	public void setScoreKorean(int scoreKorean){ this.scoreKorean = scoreKorean; }
	public void setScoreMath(int scoreMath){ this.scoreMath = scoreMath; }
	public void setScoreEnglish(int scoreEnglish){ this.scoreEnglish = scoreEnglish; }
 
	// getter 메서드
	public String getName(){ return this.name; }
	public int getScoreKorean(){ return this.scoreKorean; }
	public int getScoreMath(){ return this.scoreMath; }
	public int getScoreEnglish(){ return this.scoreEnglish; }
}

처럼 get{fieldNameCamelCased} / set{fieldNameCamelCased} 이름의 틀을 두고 해당 필드의 값을 읽어들이거나 수정할 때 해당 메서드들을 사용한다. 여기서 특정 필드에 대한 쓰기/읽기 권한을 없애고 싶다면 그냥 해당 getter / setter 메서드를 지우면 된다. 혹은 public 접근 제어 속성을 protecteddefault로 바꾸어 쓰기/읽기 권한의 범위를 설정할 수도 있다.

Kotlin으로 이걸 쓴다면…

class StudentScore(
	var name: String,
	var scoreKorean: Int,
	var scoreMath: Int,
	var scoreEnglish: Int
)

로 저 Java 코드를 대신할 수 있다. 생성자, setter, getter 메서드를 모두 써야 했던 Java 코드와 비교해보면 확실히 간단하다!

  1. 기본적인 class <className> { /* fields or methods */ }의 틀에서

    • <className> 바로 옆에 괄호로 묶은 property(자바의 field)들을 붙인다.
    • 별다른 추가 함수나 프로퍼티가 없을 경우 중괄호를 생략할 수 있다.

    를 통해 생성자 구현을 간략화할 수 있다(이걸 Kotlin에선 primary constructor라고 부른다]).

  2. 별다른 추가 구문이 없을 경우 프로퍼티는

    1. public 접근 제어 속성을 가진다(Java는 기본이 default이다).
    2. 기본 settergetter를 가진다. 명시적으로 만들지 않아도 가지고 있다가, 해당 프로퍼티의 값을 읽어들이거나 값 수정을 시도할 때 이 gettersetter를 부름으로써 이런 접근이 직접적이지 않게 만든다. hans.scoreMath = 90이라는 구문은 hans.scoreMath에 값을 직접 씌우는 게 아니라 scoreMathsetter 함수를 호출하여 내부에서 hans.scoreMath의 값을 바꾸는 식인 셈이다. public 속성을 가지지만 위의 Java 코드와 비슷하게 데이터 은닉이 가능하다.

    의 특성을 가진다. 만약 프로퍼티에 접근 권한을 두고 싶다면 - 예를 들어 영어 점수(scoreEnglish)의 (외부를 통한) 쓰기 권한을 제한하고 싶다면 - 이렇게 쓰면 된다:

    class StudentScore {
    	var name: String,
    	var scoreKorean: Int,
    	var scoreMath: Int,
    	scoreEnglish: Int	
    } {
    	var scoreEnglish: Int = scoreEnglish
    		private set
    }

    생성자에서가 아닌 클래스 본문에서 (생성자로 받은) 값으로 프로퍼티를 초기화하는 방식으로 바뀌었지만, 이렇게 하면 아래의 private set 처럼 getter / setter의 접근 권한을 설정할 수 있다(primary constructor 안에선 할 수 없다). 심지어는 저 gettersetter자신이 원하는 방향으로 구동하도록 바꿀 수도 있다!


… 어쩌다 보니 2개 - 생성자 구현부를 줄일 수 있다 + getter / setter 함수를 명시적으로 쓰지 않아도 된다 - 로 분리하려다가 하나로 합쳐서 쓰게 됐다. 여기서 본 Java - Kotlin 코드 비교가 어제 이야기했던 이 언어를 배워보고 싶은 이유였다. 공식 문서도 강의도 보고 하면서 새로 배우는 게 많아지는 것이 즐겁긴 한데즐 겁 다 한 편으로는 좀 걱정이 되기도 한다. 이게 “기초”편이고 “심화”편은 아직도 들어가지 않았다고 했으니까.

모르겠다, 또 어떤 새로운 사실들을 알게 될까?