_를 삽입하여 만들 수 있다.여기서 문제가 발생했다.
과제를 진행하는 중 Public으로 선언된 변수를 사용하는 중에 특이한 점을 발견했다:
class Computer extends TangibleAsset {
final String makerName;
Computer({
required super.name,
required super.price,
required super.color,
required super.weight,
required this.makerName,
});
}
위 코드에서 makerName 속성에 마우스를 hover 해보니 설명에는 getter 함수로 연결시켜 준다고 표시되었다. 내부적으로 getter와 setter를 만들어주는 건가 싶어서 찾아보게 되었다.

이러한 의문을 해결하기 위해 다음과 같이 조사를 진행했다.
공식문서를 찾아보려 했지만, 어느 부분을 봐야할지 감이 잡히지 않아 우선 AI에게 질문을 했다. GPT와 Claude 모두 동일한 대답을 해줬다 :
Dart의 경우 Private을 제외한 모든 변수에 getter와 setter가 내부적으로 생성되어 사용된다.
이후 해당 정보를 얻은 곳의 링크를 달라는 질문을 통해서 공식문서의 링크를 받았다. 공식문서에서는 다음과 같이 설명하고 있다:
"Getters and setters are special methods that provide read and write access to an object's properties. Recall that each instance variable has an implicit getter, plus a setter if appropriate. You can create additional properties by implementing getters and setters, using the get and set keywords."
해석 및 축약하자면:
모든 변수는 암묵적으로 getter를 가지며, 적절한 경우(const나 final이 아닐 경우) setter도 함께 가진다.
위의 Computer 클래스를 사용하는 예시를 보면 내부적으로 생성된 getter가 어떻게 동작하는지 확인할 수 있다:
void main() {
final computer = Computer(
name: "MacBook Pro",
price: 2000000,
color: "Silver",
weight: 2,
makerName: "Apple"
);
// 내부적으로 생성된 getter 사용
print(computer.makerName); // "Apple" 출력
// final 변수이므로 setter는 생성되지 않음
// computer.makerName = "Microsoft"; // 컴파일 에러 발생
}
또 다른 Dart의 차이점은 private 접근 제한자가 클래스 레벨이 아닌 라이브러리(파일) 레벨로 적용된다는 것이다. 즉, 같은 파일 내에 있는 다른 클래스에서는 _ 접두사가 붙은 변수에도 접근할 수 있다.
// file: assets.dart
class Asset {
String _privateData = "비밀 정보";
}
class AssetManager {
void accessPrivateData() {
final asset = Asset();
print(asset._privateData); // 같은 파일 내에서는 접근 가능!
}
}
다른 파일에서는 접근할 수 없다:
// file: main.dart
import 'assets.dart';
void main() {
final asset = Asset();
// print(asset._privateData); // 컴파일 에러 발생
}
위와 같이 기본적으로 getter와 setter가 주어지는데 개발자가 직접 getter와 setter를 구현하는 이유?
변수를 반환하는 과정에서 정제가 가능하다.
DateTime _createdAt = DateTime.now();
String get formattedDate {
return "${_createdAt.year}/${_createdAt.month}/${_createdAt.day}";
}
변수에 값을 넣는 과정에서 validate(검증)이 가능하다.
int _mp = 100;
set mp(int value) {
if (value < 0) {
throw Exception('마법사의 마력은 0 이상이어야 합니다.');
}
_mp = value;
}
Dart의 이러한 특성을 더 잘 이해하기 위해 다른 객체지향 언어와 비교해 보자 :
Java에서는 필드와 getter/setter를 명시적으로 정의해야 한다:
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
C#에서는 속성(Property) 개념을 통해 비슷한 기능을 제공한다:
public class Person {
// 자동 구현 속성
public string Name { get; set; }
// 읽기 전용 속성
public string Id { get; private set; }
}
Kotlin은 Dart와 유사하게 변수에 대한 getter와 setter를 자동으로 생성한다:
class Person {
var name: String = "" // 자동으로 getter와 setter 생성
val id: String = "123" // val은 불변이므로 getter만 생성
}
Dart의 이러한 특성은 언어 설계 철학과 밀접하게 연관되어 있다. Dart는 처음부터 개발자 경험(Developer Experience)을 향상시키고, 코드의 간결성을 추구하면서도 객체지향 프로그래밍의 원칙을 지키는 것을 목표로 했다.
자동 getter/setter 생성은 다음과 같은 이점을 제공한다:
1. 코드 간결성: 반복적인 보일러플레이트 코드를 줄임
2. 일관된 접근 방식: 필드나 속성이든 동일한 구문(object.property)으로 접근
3. 유연성: 나중에 단순 필드를 계산된 속성으로 변경해도 API가 깨지지 않음
이러한 특성은 특히 Flutter와 같은 프레임워크에서 UI 개발 시 코드의 가독성과 유지보수성을 크게 향상시킨다.
Dart 언어는 객체지향 프로그래밍의 캡슐화 원칙을 유지하면서도 개발자 경험을 향상시키기 위해 자동으로 getter와 setter를 생성하는 접근 방식을 채택했다. 이는 코드의 간결성과 가독성을 높이고, 추후 요구사항 변경 시 API 호환성을 유지하는 데 도움이 된다.
특히 Flutter와 같은 UI 프레임워크에서 이러한 특성은 상태 관리와 모델 설계에 매우 유용하게 활용될 수 있다. Dart의 이러한 특성을 이해하고 적절히 활용한다면, 더 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있을 것이다.