Flutter Equatable 플러그인, 도대체 어디에 쓰는건가요?

Written by 코드팩토리 JC

1월 15, 2024

Flutter Equatable

서론

안녕하세요 코드팩토리입니다. 오늘은 Equatable 플러그인 사용법에대한 강의를 가져왔어요. 외부 플러그인들을 보거나 튜토리얼을 보면 클래스들이 Equatable 부모 클래스를 익스텐드하는걸 자주 볼 수 있는데 커뮤니티에서도 종종 질문이 들어와서 왜 Equatable 플러그인을 사용해야하는지 설명을 해보려고 합니다.

Equatable 이란?

Equatable 플러그인은 한 인스턴스와 다른 인스턴스가 같은 인스턴스인지 판단을 쉽게 할 수 있게 해주는 플러그인입니다. 일반적으로 인스턴스를 두번 생산하고 이 둘을 ‘==’ 로 비교를 하면 항상 false 가 나옵니다. 왜냐면 primitive 값이 아닌이상 값을 베이스로 비교를 하는게 아니라 메모리의 위치를 기반으로 비교를 하게됩니다. 예를들어 만약에 new Person(name:'CF') == new Person(name:'CF') 라는 코드를 작성했다면 따로 equality 에 대한 정의를 하지 않는이상 절대적으로 false 값이 나옵니다.

해법

OOP 라는 명칭이 생겨난 이유는 모든 클래스는 기본적으로 Object 를 extend 하기 때문입니다. 이 뜻은 Object 라는 최상위 클래스가 제공해주는 모든 파라미터들을 모든 클래스들이 사용할 수 있다는 뜻도 되죠. 대부분의 언어에서는 이 Object 라는 클래스에 한 인스턴스와 다른 인스턴스를 비교하는 알고리즘이 정의가 되어있습니다. Dart 언어에서는 operator 라는 함수에 정의가 되어있고 이를 override 를 함으로서 값의 비교 알고리즘을 자유롭게 변경할 수 있습니다.

Operator 함수 override 하기

class Person {
  final int id;
  final String name;
  final int age;

  Person({
    required this.id,
    required this.name,
    required this.age,
  });

  @override
  bool operator ==(Object other) {
    return other is Person && other.id == this.id;
  }

  @override
  int get hashCode {
    return this.id;
  }
}
Dart

위와같이 Person 클래스를 제작하면 id 를 기반으로 Person 클래스의 인스턴스들을 비교할 수 있습니다.

final person1 = Person(id: 1, name: 'Code Factory', age: 99);
final person2 = Person(id: 1, name: 'Code Factory 2', age: 99);

print(person1 == person2);
Dart

위 코드에서 person1 과 person2 는 같다는 결과가 나옵니다. name 이나 age 파라미터를 어떻게 바꿔도 Person 클래스는 id 값으로만 비교하게 operator == 함수를 정의했기 때문입니다.

hashcode 함수

operator == 함수는 클래스의 equality 를 비교하는데 사용된다는걸 이제 알았습니다. 그럼 hashcode 함수는 어디에 사용하는걸까요? Hashcode 는 Map 또는 Set 에서 키의 역할을 하게됩니다. Map 이나 Set 은 키가 중복으로 저장될 수 없기때문에 Set 이나 Map 의 키로 오브젝트가 저장되었을때 어떻게 키값을 정의할지가 중요합니다. 저희가 정의한 Person 클래스에서는 id 를 기반으로 키값을 정의하였고 그렇기때문에 아래 코드에 person1 과 person2 를 map 에 넣어도 map 의 길이는 1로 나옵니다. Id 가 같으면 같은 hashcode 가 생성되게 정의를 했기때문이죠.

final person1 = Person(id: 1, name: 'Code Factory', age: 99);
final person2 = Person(id: 1, name: 'Code Factory 2', age: 99);

final map = {
  person1: true,
  person2: true,
};

print(map.length);
Dart

Equatable 이 필요한 이유

지금 Person 클래스는 id 만을 사용해서 operator == 과 hashcode 메소드를 정의하고 있습니다. 하지만 만약에 모든 값들을 비교 범위에 포함시키고싶으면 어떻게 해야할까요?

class Person {
  final int id;
  final String name;
  final int age;

  Person({
    required this.id,
    required this.name,
    required this.age,
  });

  @override
  bool operator ==(Object other) {
    return other is Person && other.id == this.id 
      && other.name == this.name 
      && other.age == this.age;
  }

  @override
  int get hashCode {
    return this.id;
  }
}
Dart

이런식으로 operator == 메소드를 변경해야합니다. 파라미터가 많아질수록 작성해할 코드도 길어지겠죠. hashcode 또한 문제입니다. 절대적으로 int 값을 돌려줘야하는데 String 같은 int 로 환산되기 어려운 값들은 어떻게 정의 해줘야할까요?

이 문제를 해결해주는게 바로 Equatable 라이브러리입니다.

사용법

Equatable 이 왜 필요한지 이해만 하고나면 Equatable 함수의 사용법은 상당히 쉽습니다. Equatable 클래스를 상속을 받고 props 라는 메소드를 override 해주면 됩니다. props 메소드는 리스트를 받게되는데 이 리스트에 들어가는 모든 값들의 조합이 operator == 과 hashcode 함수를 생성하는데 사용됩니다.

class Person extends Equatable{
  final int id;
  final String name;
  final int age;

  Person({
    required this.id,
    required this.name,
    required this.age,
  });

  @override
  List<Object> get props => [this.id, this.name, this.age];
}
Dart

굉장히 간단하죠? 위 코드를 작성한 뒤 아래 비교를 실험해보면 저희가 예상하는 값들이 나오는걸 볼 수 있습니다.

final person1 = Person(id: 1, name: 'Code Factory', age: 99);
final person2 = Person(id: 1, name: 'Code Factory 2', age: 99);
final person3 = Person(id: 1, name: 'Code Factory', age: 99);

/// False
print(person1 == person2);

/// True
print(person1 == person3);
Dart

어떤가요? 편리하신가요? 안써도 그만이긴 하지만 한번 사용하기 시작하면 몸에 금방 베기는 플러그인입니다!

관련 포스트

플러터에서의 Immutable Programming: copyWith 함수 마스터하기!

플러터에서의 Immutable Programming: copyWith 함수 마스터하기!

서론 불변 프로그래밍: 현대 개발의 핵심 현대 소프트웨어 개발에서 불변 프로그래밍(Immutable Programming)의 중요성은 간과할 수 없는 요소입니다. 플러터(Flutter)에서도 마찬가지로 불변 프로그래밍 개념이 매우 중요하며, copyWith 함수는 이러한 불변성을 유지하는 데 핵심적인 역할을 합니다. 이 글에서는 플러터를 배우기 시작하는 개발자들에게 불변 프로그래밍의 중요성을 강조하고, copyWith 함수의 역할과 사용 방법에 대해 설명 해보겠습니다!...

ChatGPT가 이야기하는 2024년 개발자 로드맵

ChatGPT가 이야기하는 2024년 개발자 로드맵

서론 개발자의 여정을 시작하며 안녕하세요, 미래의 개발자 여러분! 오늘부터 시작하는 여러분의 개발 여정에 함께할 수 있어서 기쁩니다. 2023년은 기술이 매우 빠르게 변화하는 해였으며, 이러한 변화 속에서 개발자가 되기 위한 길은 더욱 다채롭고 흥미로워졌습니다. 이 로드맵은 초보자인 여러분이 개발의 세계에 첫발을 내딛는 데 필요한 기초부터 시작해, 점차 심화 단계로 나아가는 길을 안내해 드릴 것입니다. 백엔드 개발 이 글은 단순히 기술을 배우는 것 이상의 의미를 가집니다....

Flutter Freezed 플러그인! Entity Code Generation은 이거 하나로 끝!

Flutter Freezed 플러그인! Entity Code Generation은 이거 하나로 끝!

https://youtu.be/i5p6wXLAX7I 서론 Flutter 는 Code Generation 기능이 상당히 많이 활성화되어 있어요. 흔히들 많이 사용하는 json_serializable 라이브러리도 있고 retrofit 및 chopper 라이브러리도 있습니다. 오늘 알려드릴 freezed 또한 데이터 클래스에 편의 기능들을 제공해주는 code generation 라이브러리입니다. Freezed vs Json Serializable Code Generation 이라는...