본문 바로가기

Flutter

Equatable Package

Equqatable?

flutter_bloc을 만든 사람(Felix Angelov)이 만들었다. 이전에 State가 새로이 생성된 State와 같으면 위젯 트리를 리빌드하지 않는다.

만약 핸들링하고 있는 State가 int나 String같은 Primitive 타입이면 두 State가 동일하다는 판단이 간단하다. 그런데 핸들링하는 State의 타입이 Class인 경우에 Class의 두개의 인스턴스가 같은지를 어떻게 판단해야 할까요? flutter_bloc에서는 그것을 equatable을 사용해 판단한다.

Object equality(http://dart.dev/guides/language/effective-dart/design#equality)

 

특징

- dart에서 한 클래스에 인스턴스들을 비교하기 위해서는 equality operator == 와 hashCode를 overrides하는 것이 필요합니다.

그런데 이 작업이 클래스의 멤버가 많아지면 굉장히 번거로운 작업이 됩니다. 또 클래스를 새로 만들 때마다 매번 동일한 작업을 반복을 해야합니다. 이런 작업을 쉽게 해주는게 Equatable패키지입니다.

- 또 주의해야 할 점은 Equatable은 immutable objects에만 적용되도록 디자인 되었다는 점입니다.

그렇기 때문에 Equatable을 사용하기 위한 중요한 전제 조건 중 하나가 모든 멤버가 final이여야 한다는 점입니다.

- Equatable은 클래스의 모든 프로퍼티를 포함한 toString method를 제공해줍니다. 즉, 클래스에 대한 human readable한 representation을 제공해 줍니다.

- 그런데 다트는 여러개의 클래스를 동시에 extends 할 수 없기 때문에 어떤 클래스가 이미 다른 클래스를 extends하고 있는 것을 대비해서EquatableMixin이라는 mixin을 제공합니다.

 

원문

- Equatable overrides equality operator == and hashCode. So, it saves the trouble of having to override the two one by one.

- Equatable can only be used on immutable objects. That is, all members must be final.

- Equatable provides a toString method that includes all properties of a class. That is, it provides a human-readable representation of the class.

- Finally, a mixin called EquatableMixin is provided in case a class already extends another class.

 

Example

dart run 실행 결과 user1과 user2의 해시코드가 다르다.

print(user1 == user2); => false

print(user1.hashCode); => 40440065

print(user2.hashCode); => 909584937

 

앞에서 얘기한 것처럼 두 개의 오브젝트가 같으려면 해시코드도 같아야 한다는 걸 비로소 여기서 해시코드가 눈으로 와닿습니다.

그런데 두 개의 인스턴스는 같다고 보는 게 우리의 직관에 부합합니다. 쉽게 말해서 그냥 보면 같다고 보는 게 맞다는 거죠.

모든 프로퍼티가 같으면 같다고 보는 게 많은 경우에서 합리적입니다. Equatable패키지는 그런 비교를 쉽게 해준다고 보면 됩니다.

 

변경 전 user.dart
Equatable패키지를 추가하니 생기는 오류

Missing concrete implementation of 'getter Equatable.props'.
Try implementing the missing method, or make the class abstract.

'getter Equatable.props'의 구체적인 구현이 누락되었습니다.
누락된 메소드를 구현하거나 클래스를 추상화하십시오.

노란 전구를 클릭해 Generate Equatable을 클릭해줍니다.

Equatable은 props getter가 리턴하는 리스트에 포함된 엘리먼트들이 같으면 같은 오브젝트라고 판단합니다.

이 상태에서 다시 dart run을 실행 해보겠습니다.

 

맨 끝에 false가 true가 되고 해시코드가 같아진 것을 볼 수 있습니다.

dart에서 한 클래스에 인스턴스들을 비교하기 위해서는 equality operator == 와 hashCode를 overrides하는 것이 필요합니다.

위에서 언급한 것처럼 Equatable이 해준 작업을 수동으로 하려면 Equality Operator와 HashCode 이 두가지를 overrides해야 합니다.

그렇게 되면 필드가 많은 클래스의 경우 굉장히 번거로운 일이 되는데 Equatable패키지를 사용하면 간단하게 처리할 수 있습니다.

추가적으로 toString 메소드를 제공한다는 건 무슨 말일까요?

 

print(user1);을 했는데 터미널에는 User만 찍힙니다.

User라는 클래스 이름만 표시되는 걸로는 User 오브젝트의 모양을 추정하기 쉽지 않습니다. 이런 경우를 대비해 있는 게 Equatable에서 제공하는 toString 메소드입니다. Equatable은 props에 나열된 엘리먼트들도 함께 표시하는 toString메소드를 제공해줍니다.

 

이것을 사용하기 위해 아래와 같이 코드를 user.dart에 넣어줍니다.

@ovverride
bool get stringify => true;

User(1, name, email)

User에 만들어 놓았던  props들을 전부 확인할 수 있습니다.

이것을 보고 Human readable하게 즉, 사람이 읽기 쉬운 형태로 출력해줍니다. 

아래처럼 표시도 할 수 있는데 아래처럼 하게되면 좀더 props가 직관적으로 알 수 있습니다.

근데 이게 매번 클래스마다 이렇게 일일히 써주려면 굉장히 반복적인 작업입니다.

이걸 해소해주는 게 비주얼 스튜디오에 있는 어플같은 extention이 해결해줍니다.

Dart Data Class Generator

위에서 사용했던 노란 전구 버튼이 이 익스텐션 덕분에 여러가지가 가능해집니다.

 

 

요약 정리

- 생산성을 높여주는 Equatable과 Dart Data Class Generator 활용 잘하기

- Equatable 대표 기능 두가지

 1. Equatable처리해준 클래스는 한 클래스에서 생성된 여러 인스턴스들간의 해시코드를 같게 함으로 같다는 걸 쉽게 비교해줌.

 2. toString메소드가 적용된 어떤 클래스를 출력하면 휴먼리더블한 인간이 읽기 쉬운 형태로 변화시켜 출력 도와줌.

 

참고자료

https://pub.dev/packages/equatable