제네릭이 주는 편리함과 코드 재사용성에 대해 알아보며 제네릭 사용시 유의점에 대해 알아 볼 것 입니다.
제네릭의 장점을 통해 사용하는 이유를 알아 봅시다.
제네릭의 장점
1. 제네릭 유형을 적절하게 지정하면 생산성이 올라갑니다.
2. 제네릭을 사용하여 코드 중복을 줄일 수 있습니다.
아래 예제에서 Cache를 얻어오는 클래스를 만들때 객체,스트링 등 다양한 타입의 캐시를 받아올 때
제네릭을 활용해 받아오면 어떤 타입이든 하나의 클래스를 공유해 재사용성을 높일
void main(List<String> args) {
var names = <String>[]; List<String>
names.add("Gavri");
// names.add(1); // int type error
}
abstract class ObjectCache {
Object getByKey(String key);
}
abstract class StringCache {
String getByKey(String key);
}
// 제네릭 활용
abstract class Cache<T> {
T getByKey(String key);
}
아래 예제를 통해 컬렉션에 타입 지정 및 생성자 제네릭 지정 방식에 대해 배워보겠습니다.
var names = <String>["Seth", "Kathy"]; // List
var uniqueNames = <String>{"Seth", "Kathy"}; // Set
var pages = <String, String>{
"index.html": "HomePage",
"robots.txt": "Hints for web robots",
};
// 생성자와 함께 매개변수화된 유형 사용
var nameSet = Set<String>.from(names);
var views = Map<int, View>();
var names = <String>[]; // 이 타입 또한 List<String> 으로 인식합니다.
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
제네릭 형식을 구현할 때는 인수로 제공할 수 있는 형식을 제한하여 인수가 특정 형식의 하위 형식이어야 합니다.
extends 를 활용해 위 내용을 구현 할 수 있습니다.
class Foo<T extends Object> {
// null을 제외한 모든 타입은 Object를 상속하기에 null 제외하기 위해 Object 상속
}
class SomeBaseClass {}
class Boo<T extends SomeBaseClass> {}
class Extender extends SomeBaseClass {}
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>(); // 하위 클래스
var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'
T Function<T>(List<T> ts) {
T tmp = ts[0]
return tmp;
}
제네릭은 여러 위치에서 사용 가능합니다