어떤 데이터를 주고 받을 때 클래스를 생성해서 다루는 일은 빈번하게 이루어진다. 하지만 잘못사용하게 된다면 데이터의 누락 또는 잘못된 사용으로 값이 변조될 수 있다.
Dart 에서 사용되는 cascade operator 및 활용 가능한 데이터 모델 클래스에 대해 다뤄보고자 한다.
예를 들어 병이란 데이터는 이름과 용량이란 값을 가지고 있다고 가정해보자. 그럼 아래와 같이 클래스를 작성할 수 있다.
class Bottle {
String? name;
final int capacity;
}
용량은 병이 한번 제조된 후 변경될 수 없을 거라 생각해 final로 선언해주었다.
이와 같은 상황을 가정해 새로운 인스턴스를 생성할 수 있는 메소드를 추가해보자!
위 2개의 기능을 충족시켜줄 수 있는 메소드를 추가해보면 아래와 같이 작성할 수 있다.
factory Bottle.from(String name) => Bottle(
capacity: 10,
name: name,
);
Bottle addName(String updatedName) => Bottle(
capacity: capacity,
name: updatedName,
);
factory
패턴을 사용해서 기본 용량 10
을 가진 새로운 병을 생성하는 메소드와 이미 있는 병에서 이름만 수정해서 새로운 병을 생성해주는 메소드를 작성했다. 이제 이 2개를 활용해보자.
더 정확한 인스턴스의 상태를 알 수 있도록 간단하게 print 해볼 수 있는 메소드도 추가해보았는데 완성된 클래스는 아래와 같다.
class Bottle {
String? name;
final int capacity;
Bottle({
required this.capacity,
this.name,
});
factory Bottle.from(String name) => Bottle(
capacity: 10,
name: name,
);
Bottle addName(String updatedName) => Bottle(
capacity: capacity,
name: updatedName,
);
void printInfo() => print(
'hashCode: $hashCode, capacity: $capacity, name: $name',
);
}
위 함수를 통해서 총 6가지의 경우를 테스트 해보려 한다.
테스트 해볼 코드는 아래와 같다.
void main() {
/// 1. create new instance
Bottle water = Bottle(capacity: 10);
water.printInfo();
/// 2. using cascade operator
Bottle icis = Bottle(capacity: 12)..name = 'icis';
icis.printInfo();
/// 3. using same instance of `icis` and change name to [evian]
Bottle evian = icis..name = 'evian';
evian.printInfo();
/// 4. copy value and create new instance
Bottle icis2 = icis.addName('second icis');
icis2.printInfo();
/// 5. copy instance
Bottle icis3 = icis..addName('third icis');
icis3.printInfo();
/// 6. create new instance
Bottle samdasu = Bottle.from('samdasu');
samdasu.printInfo();
}
그리고 결과는 다음과 같다.
hashCode: 490920693, capacity: 10, name: null
hashCode: 978607171, capacity: 12, name: icis
hashCode: 978607171, capacity: 12, name: evian
hashCode: 1050812338, capacity: 12, name: second icis
hashCode: 978607171, capacity: 12, name: evian
hashCode: 761191122, capacity: 10, name: samdasu
여기서 3번 같은 경우 icis
의 인스턴스를 복사해 이름을 수정해주었지만 icis
의 이름 또한 evian
으로 변경되었다.
그 이유는 Shallow Copy 가 일어났기 때문이다. 같은 메모리 주소를 참조하고 있으며 icis
의 인스턴스를 복사해 name
의 값을 변경해주었다.
name
이 third icis
로 변경되지 않았을까?4번 같은 경우에는 addName( )
메소드가 새로운 인스턴스를 반환한다.
icis..
과정에서 기존 icis
의 인스턴스가 반환된다.
icis..addName(_)
하지만 여기서 addName
을 통해서 새로운 인스턴스가 반환이 되는데, 이미 icis
의 인스턴스가 반환된 상태이므로 icis3
에 할당되는 인스턴스는 icis
인스턴스이다.
만약 데이터 클래스 내에 콜백 함수나 수정될 수 있는 데이터가 있어 cascade(..) 연산자를 통해 수정을 한다면 5번과 같은 경우를 주의해서 사용해야한다.