노마드코더 챌린지를 하는 도중 과제가 있었다. 조건은 아래와 같다.
Using everything we learned, make a Dictionary class with the following methods:
위의 조건을 충족하면서 클래스 Dictionary
를 만들어야한다. 즉 추가, 검색, 수정, 삭제, 총 단어 수, 등의 작업을 수행할 수 있는 클래스를 만들자!
타입 별칭을 사용할 수 있는 typedef
를 통해 재사용성을 높여보자!
조건을 봤을 때 많이 쓰일 거 같은 자료구조가 Map<String, String>
이다.
왜냐하면 클래스 기본 속성으로 선언할 _dictionary
가 리스트 안에 들어가는 Map<String, String>
구조이기도 하고, bulk~
메소드들을 봤을 때 리스트[] 안에 Map<String, String>
이기 때문에 typedef
을 써서 재사용성을 높여보자!
// typedef 사용
typedef DictionaryData = Map<String, String>;
사실 추상은 필수가 아닌데, 일단 OOP의 꽃은 빼놓을 수가 없으니 먼저 정의해보자.
위와 같이 계획을 잡았다. 메소드는 위에 조건을 보며 하나씩 대조해가며 만들었다. 또 Named를 많이 쓴다고들 하니 일단 마스터하려고 Named Parameter로 만들었다.
// Abstract class 정의
abstract class AbstractDictionary {
// Named parameter 사용
void add({required String term, required String definition});
String get({required String term});
void delete({required String term});
void update({required String term, required String definition});
void showAll();
int count();
void upsert({required String term, required String definition});
bool exists({required String term});
void bulkAdd(List<DictionaryData> terms);
void bulkDelete(List<String> terms);
}
void
, String
, int
등 반환 타입에 따라 작성했고, 뭐가 들어올지에 따라서도 만들었다.
특히 bulk~
메소드를 만들면서 조금 구글링의 힘을 빌리긴 했는데 간단하게 만들었다. 별칭 선언한 DictionaryData
도 사용했다!
받는 객체를 terms
로 지정 후 나중에 메소드 구현할 때 쓸 것이다!
가장 핵심이자 꽃인 Dictionary
클래스를 구현해보자!
_dictionary
필드를 private으로 선언하여 캡슐화(encapsulation)를 구현함add
, get
, delete
, update
, showAll
, count
, upsert
, exists
, bulkAdd
, bulkDelete
메서드를 통해 사전 작업을 수행할 수 있음get
, update
는 조건을 두어 단어의 존재를 분기 처리showAll
, bulkAdd
, bulkDelete
는 for
를 사용.(for)containsKey
: exists
, update
특정 키가 존재하는지의 대한 유무를 불린으로 확인@override
를 작성해 추상클래스의 부모에게 빌려왔다는 걸 명시// Dictionary 클래스 구현
class Dictionary implements AbstractDictionary {
// 필드 정의
final DictionaryData _dictionary = {};
void add({required String term, required String definition}) {
_dictionary[term] = definition;
}
String get({required String term}) {
return _dictionary[term] ?? '해당 단어가 사전에 없습니다.';
}
void delete({required String term}) {
_dictionary.remove(term);
}
void update({required String term, required String definition}) {
if (_dictionary.containsKey(term)) {
_dictionary[term] = definition;
} else {
print('해당 단어가 사전에 없습니다.');
}
}
void showAll() {
_dictionary.forEach((term, definition) {
print('$term : $definition');
});
// for (var term in _dictionary.keys) {
// print('$term : ${_dictionary[term]}');
// }
}
int count() {
return _dictionary.length;
}
void upsert({required String term, required String definition}) {
_dictionary[term] = definition;
}
bool exists({required String term}) {
return _dictionary.containsKey(term);
}
void bulkAdd(List<DictionaryData> terms) {
for (var term in terms) {
_dictionary[term['term']!] = term['definition']!;
}
}
void bulkDelete(List<String> terms) {
for (var term in terms) {
_dictionary.remove(term);
}
}
}
끝! 재밌다! containsKey
나 ??
같이 다트에만 있는 기능을 어떻게든 넣으려고 발악했다 ㅋㅋㅋ
가장 간단하다.
그냥 Dictionary
클래스의 인스턴스를 생성한 후, 위에서 정의한 메소드들을 이용하여 사전에 단어를 추가하거나 수정하거나 삭제하거나 조회하는 등의 동작을 수행하기만 하면 된다.
void main() {
var dictionary = Dictionary();
// 단어 추가
dictionary.add(term: 'apple', definition: '사과나무의 열매');
// 단어 가져오기
print(dictionary.get(term: 'apple')); // 출력: 사과나무의 열매
// 없는 단어 가져오기
print(dictionary.get(term: 'banana')); // 출력: 해당 단어가 사전에 없습니다.
// 단어 수정
dictionary.update(
term: 'apple', definition: '사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.');
print(dictionary.get(
term: 'apple')); // 출력: apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
// 단어 추가 또는 수정
dictionary.upsert(term: 'banana', definition: '바나나');
// 단어 삭제
dictionary.delete(term: 'banana');
// 단어 존재 여부 확인
print(dictionary.exists(term: 'apple')); // 출력: true
print(dictionary.exists(term: 'banana')); // 출력: false
// 대량 단어 추가
List<DictionaryData> bulkTerms = [
{'term': 'cherry', 'definition': '체리'},
{'term': 'orange', 'definition': '오렌지'}
];
dictionary.bulkAdd(bulkTerms);
dictionary.showAll();
// apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
// cherry: 체리
// orange: 오렌지
// 단어 개수 세기
print(dictionary.count()); // 출력: 3
// 대량 단어 삭제
List<String> bulkDeleteTerms = ['cherry', 'orange'];
dictionary.bulkDelete(bulkDeleteTerms);
dictionary.showAll(); // apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
}
모든 메소드들을 빠짐없이 사용해봤다. 주석도 처리해놨으니 흐름만 타고가도 알 것이다!
// typedef 사용
typedef DictionaryData = Map<String, String>;
// Abstract class 정의
abstract class AbstractDictionary {
// Named parameter 사용
void add({required String term, required String definition});
String get({required String term});
void delete({required String term});
void update({required String term, required String definition});
void showAll();
int count();
void upsert({required String term, required String definition});
bool exists({required String term});
void bulkAdd(List<DictionaryData> terms);
void bulkDelete(List<String> terms);
}
// Dictionary 클래스 구현
class Dictionary implements AbstractDictionary {
// 필드 정의
final DictionaryData _dictionary = {};
void add({required String term, required String definition}) {
_dictionary[term] = definition;
}
String get({required String term}) {
return _dictionary[term] ?? '해당 단어가 사전에 없습니다.';
}
void delete({required String term}) {
_dictionary.remove(term);
}
void update({required String term, required String definition}) {
if (_dictionary.containsKey(term)) {
_dictionary[term] = definition;
} else {
print('해당 단어가 사전에 없습니다.');
}
}
void showAll() {
_dictionary.forEach((term, definition) {
print('$term : $definition');
});
// for (var term in _dictionary.keys) {
// print('$term : ${_dictionary[term]}');
// }
}
int count() {
return _dictionary.length;
}
void upsert({required String term, required String definition}) {
_dictionary[term] = definition;
}
bool exists({required String term}) {
return _dictionary.containsKey(term);
}
void bulkAdd(List<DictionaryData> terms) {
for (var term in terms) {
_dictionary[term['term']!] = term['definition']!;
}
}
void bulkDelete(List<String> terms) {
for (var term in terms) {
_dictionary.remove(term);
}
}
}
void main() {
var dictionary = Dictionary();
// 단어 추가
dictionary.add(term: 'apple', definition: '사과나무의 열매');
// 단어 가져오기
print(dictionary.get(term: 'apple')); // 출력: 사과나무의 열매
// 없는 단어 가져오기
print(dictionary.get(term: 'banana')); // 출력: 해당 단어가 사전에 없습니다.
// 단어 수정
dictionary.update(
term: 'apple', definition: '사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.');
print(dictionary.get(
term: 'apple')); // 출력: apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
// 단어 추가 또는 수정
dictionary.upsert(term: 'banana', definition: '바나나');
// 단어 삭제
dictionary.delete(term: 'banana');
// 단어 존재 여부 확인
print(dictionary.exists(term: 'apple')); // 출력: true
print(dictionary.exists(term: 'banana')); // 출력: false
// 대량 단어 추가
List<DictionaryData> bulkTerms = [
{'term': 'cherry', 'definition': '체리'},
{'term': 'orange', 'definition': '오렌지'}
];
dictionary.bulkAdd(bulkTerms);
dictionary.showAll();
// apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
// cherry: 체리
// orange: 오렌지
// 단어 개수 세기
print(dictionary.count()); // 출력: 3
// 대량 단어 삭제
List<String> bulkDeleteTerms = ['cherry', 'orange'];
dictionary.bulkDelete(bulkDeleteTerms);
dictionary.showAll(); // apple: 사과나무의 열매로, 세계적으로 널리 재배되는 열매 가운데 하나이다.
}
추상 클래스와 자식 클래스의 구분을 통해 추상화와 캡슐화를 구현하고, 맵(Map) 객체를 사용해서 단어와 정의를 저장했다.
이를 통해 다양한 기능을 더 만들어내거나 상속, Mixins 할 수 있고, main 함수에서 dictionary
인스턴스를 조작할 수도 있다.
아쉬운 건 Named Constructor도 실습을 해보고 싶었는데 그거까지 하기에는 좀 오바인 거 같아서 패스! 다음엔 진짜 플러터다!
안녕하세요. 혹시 bulkAdd 메소드에서 사용하신 문법이 뭔지 알 수 있을까요?