규약은 개발자들의 단순한 합의. 그러나 위반할 수도 있다.
ex) 리플렉션 활용
class Employee {
private val id: Int = 2
override fun toString() = "User(id=$id)"
private un privateFunction() {
println("Private function called")
}
}
fun callPrivateFunction(employee: Employee) {
employee::class.declaredMemberFunctions
.first{ it.name = "privateFunction" }
.apply { isAccessible = true }
.set(employee, newId)
}
fun main() {
val employee = Employee()
callPrivateFunction(employee)
// print : Private Function called
changeEmployeeId(employee, 1)
print(employee) // print: User(id=1)
}
무언가를 할 수 있다는 건 그것을 해도 괜찮다는 의미는 아니다. 현재 코드는 private 프로퍼티와 private 함수의 이름과 같은 세부적인 정보에 매우 크게 의존하고 있다. 이러한 이름은 규약이라고 할 수 없어서 시한 폭탄과도 같다.
규약은 보증과 같다. 규약을 위반하면 코드가 작동을 멈췄을 때 문제가 된다.
클래스를 상속하거나 다른 라이브러리의 인터페이스를 구현할 때는 규약을 반드시 지켜야 한다. 만약 규약을 지키지 않는다면 제대로 동작하지 않을 수 있다.
class Id(val id: Int) {
override fun equals(other: Any?) = other is Id && other.id == id
}
val set = mutableSetOf(Id(1))
set.add(Id(1))
set.add(Id(1))
print(set.size) // 3
위 코드처럼 Set
는 중복을 허용하지 않는데 equals
가 제대로 구현되지 않아서 중복이 허용된다.
참고로 현재 hashCode
와 equals
구현에 일관성이 없다.
프로그램을 안정적으로 유지하고 싶다면, 규약을 지키자! 규약을 깰 수 밖에 없다면 잘 문서화하자.
이러한 정보는 코드를 유지하고 관리하는 사람에게 큰 도움이 된다. 그 사람이 몇 년 뒤의 당신이 될 수도 있다는 것을 기억하자..