๐ŸŽŠ [Flutter&Dart] ํด๋ž˜์Šค(class)์˜ ๋ชจ๋“  ๊ฒƒ !

Tygerยท2024๋…„ 4์›” 2์ผ
2

Flutter

๋ชฉ๋ก ๋ณด๊ธฐ
57/57
post-thumbnail

๐ŸŽŠ ํด๋ž˜์Šค(class)์˜ ๋ชจ๋“  ๊ฒƒ !

Classes | Dart
Mixins | Dart

[Dart] Class ์ด ์ •๋ฆฌ (์ƒ์† / ์žฌ์ •์˜ / ์ถ”์ƒํ™”)
Instance ๊ด€์ ์—์„œ Class, Singleton, Static ์•Œ์•„๋ณด๊ธฐ

Singleton Pattern(์‹ฑ๊ธ€ํ†ค ํŒจํ„ด) ?
Factory Pattern(ํŒฉํ† ๋ฆฌ ํŒจํ„ด) ?

copyWith์— NULL ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Flutter&Dart Class์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Dart OOP(Object Oriented Programming) ?

๋จผ์ € Flutter๋Š” Dart์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐœ๋ฐœ๋œ FrameWork์ด๋ฉฐ, Flutter FrameWork์—์„œ๋„ Dart๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐœ๋ฐœ๋˜์–ด ์ง€๊ณ  ์žˆ๋‹ค.

Dart ์–ธ์–ด์—์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๊ฐ์ฒด(object)์ด๋‹ค.

Dart๋Š” ํด๋ž˜์Šค(class)์™€ Mixin๊ธฐ๋ฐ˜์˜ ์ƒ์†์„ ์ง€์›ํ•˜๋Š” ์™„์ „ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด(Super OOP)์ด๋ฉฐ, ๋ชจ๋“  ๊ฐ์ฒด๋Š” ํด๋ž˜์Šค(class)์˜ ์ธ์Šคํ„ด์Šค(instance)์ด๊ณ , NULL์„ ์ œ์™ธํ•œ ๋ชจ๋“  class๋Š” Object์—์„œ ๋น„๋กฏ๋œ๋‹ค.
Mixin ๊ธฐ๋ฐ˜ ์ƒ์†์€ ๋ชจ๋“  ํด๋ž˜์Šค(class)๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด(Object)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, ํด๋ž˜์Šค(class)์˜ ๋ฐ”๋””๋Š” ๋‹ค์–‘ํ•œ ํด๋ž˜์Šค(class) ๊ณ„์ธต์—์„œ ์žฌ์‚ฌ์šฉ ๋  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ๊ณต์‹ ๋ฌธ์„œ์—์„œ ์„ค๋ช…ํ•˜๊ณ  ์žˆ๋‹ค.

" Dart is an object-oriented language with classes and mixin-based inheritance. Every object is an instance of a class, and all classes except Null descend from Object. Mixin-based inheritance means that although every class (except for the top class, Object?) has exactly one superclass, a class body can be reused in multiple class hierarchies. Extension methods are a way to add functionality to a class without changing the class or creating a subclass. Class modifiers allow you to control how libraries can subtype a class. "

์œ„์˜ ์„ค๋ช…์ด ์ž˜ ์ดํ•ด๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์ดํ•ด๊ฐ€ ์•ˆ๋˜๋”๋ผ๋„ ์ฒœ์ฒœํžˆ ์ž์ฃผ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฐœ๋…์„ ์Šต๋“ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ํฌ๊ฒŒ ๊ฑฑ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ , ์™ธ์šธ ํ•„์š”๋Š” ์—†๋‹ค.

Dart Class

Dart Class๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด์„œ 4๊ฐ€์ง€ ํ‚ค์›Œ๋“œ๋ฅผ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

  • object
  • class
  • constructor
  • instance

ํด๋ž˜์Šค(class)์— ๋Œ€ํ•ด์„œ ์ž์„ธํžˆ ๋‹ค๋ฃจ๋ฉด์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๊ณ , ์šฐ์„  ๊ฐœ๋… ์ •๋„๋งŒ ์•Œ๊ณ  ์žˆ๋„๋ก ํ•˜์ž.

์ž ์ž๋™์ฐจ๋ฅผ ๋งŒ๋“œ๋Š” ๊ณต์žฅ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

์ž๋™์ฐจ๋Š” ์ˆ˜ ๋งŒ๊ฐ€์ง€ ๋ถ€ํ’ˆ์˜ ์กฐํ•ฉ์œผ๋กœ ๋งŒ๋“ค์–ด ์ง„๋‹ค. ๋งŒ๋“œ๋Š” ๊ฒƒ ์™ธ์—๋„ ์ถœ๊ณ  ์ „ ํ…Œ์ŠคํŠธ ๊ณผ์ •๋„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค.
์ด๋ ‡๊ฒŒ ๋ณต์žกํ•œ ๊ตฌ์กฐ์˜ ์ž๋™์ฐจ๊ฐ€ ๋‹จ ํ•˜๋‚˜์˜ ๊ตฌ์กฐ๋กœ ์ด๋ค„์ง€์ง€ ์•Š๊ณ , ๋‚ด๋ถ€์ ์œผ๋กœ ์ข…๋ฅ˜๋„ ๋‹ค์–‘ํ•˜๊ฒŒ ์กด์žฌํ•œ๋‹ค.

๊ณต์žฅ์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์ž๋™์ฐจ๋ฅผ ์ƒ์‚ฐํ•˜๊ธฐ ์œ„ํ•œ ์ƒ์‚ฐํ‘œ๋ฅผ ๊ณตํ†ตํ™”๋œ ๊ธฐ์ค€์œผ๋กœ ๊ด€๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋ถ€ํ’ˆ ์ข…๋ฅ˜ ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ถ€ํ’ˆ ๊ฐฏ์ˆ˜, ํ…Œ์ŠคํŠธ ๊ณผ์ •๋“ฑ์˜ ์ง‘ํ•ฉ์ฒด๋ฅผ ๊ฐ์ฒด(object)๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ž๋™์ฐจ๋ฅผ ์ƒ์‚ฐํ•˜๊ธฐ ์œ„ํ•œ ์„ค๊ณ„๋„๊ฐ€ ํด๋ž˜์Šค(class)์— ํ•ด๋‹น ๋œ๋‹ค.
์„ค๊ณ„๋„๋Š” ์†์„ฑ(attribute)๊ณผ ๋™์ž‘(behavior)์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์†์„ฑ์€ ๋ฉค๋ฒ„๋ณ€์ˆ˜(member variable), ๋™์ž‘์€ ๋ฉ”์„œ๋“œ(method)๋กœ ํ‘œํ˜„ ๋œ๋‹ค.

์ž๋™์ฐจ๊ฐ€ ์ƒ์‚ฐ ๋˜๊ธฐ ์œ„ํ•ด ์ปจ๋ฒ ์ด์–ด ๋ฒจํŠธ์— ์˜ฌ๋ผ๊ฐ€๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ค๊ณ„๋„์˜ ์†์„ฑ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ์•ผ ํ•˜๋Š”๋ฐ, ์ด ๋•Œ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด ์ดˆ๊ธฐํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒ์„ฑ์ž๊ฐ€ ๋ฐ”๋กœ constructor ์ด๋‹ค.

ํด๋ž˜์Šค(class)๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ์ธ์Šคํ„ด์Šค(instance)๋ผ๊ณ  ํ•œ๋‹ค.

ํ”ํžˆ ์ธ์Šคํ„ด์Šคํ™”๋ผ๊ณ  ํ•˜๋Š” ์˜๋ฏธ๊ฐ€ ๋ฐ”๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ ค์ง€๋Š” ์ˆœ๊ฐ„์„ ์˜๋ฏธํ•œ๋‹ค.

์ ์ ˆํ•œ ์˜ˆ์‹œ์ธ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, ๊ฐ€๋ณ๊ฒŒ๋งŒ ๋ณด๊ณ  class๋ฅผ ๋งŒ๋“ค๊ณ  ๋‹ค๋ฃจ๋ฉด์„œ ๊ฐœ๋…์„ ๋” ์ •ํ™•ํžˆ ์ตํ˜€๋ณด๋„๋ก ํ•˜์ž.

๊ธ€์„ ์ž์ฃผ ๊ฒŒ์‹œํ•˜์ง€๋งŒ ํ•ญ์ƒ ๋Š๋ผ๋Š”๊ฒŒ ๊ธ€๋กœ๋งŒ ์„ค๋ช… ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ฐธ ํž˜๋“  ๊ฒƒ ๊ฐ™๋‹ค ...

Class

์ด์ œ ํด๋ž˜์Šค(class)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

๊ธฐ๋ณธ์ ์ธ ํด๋ž˜์Šค(class) ๊ตฌ์กฐ์ด๋‹ค.

ํด๋ž˜์Šค(class)๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์™€ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํด๋ž˜์Šค ๋ช…์„ ์ •ํ•  ๋•Œ์—๋Š” ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•˜๋Š” PascalCase ํ‘œ๊ธฐ๋ฒ•์„ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

class Person {
  String name = "tyger";
}

ํด๋ž˜์Šค(class)๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋„๋ก ํ•˜์ž.

Person ํด๋ž˜์Šค๋ฅผ tyger๋ผ๋Š” ๋ณ€์ˆ˜๋กœ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , ํ•ด๋‹น object(๊ฐ์ฒด)๊ฐ€ ์‚ฌ์šฉ ๋˜์–ด์งˆ ๋•Œ์— instance ๋œ๋‹ค.

(์ธ์Šคํ„ด์Šค)instance๋ž€ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น ๋˜์–ด์ง€๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

void main() {
  Person tyger = Person();
  print(tyger.name);
  // tyger
}

instance

์ธ์Šคํ„ด์Šค(instance)๋ž€ ๋ญ˜๊นŒ ?

" ์ธ์Šคํ„ด์Šค๋ž€ Class๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋˜๋ฉฐ, Class์˜ ๊ธฐ๋Šฅ๊ณผ ์†์„ฑ์„ ๋™์ผํ•˜๊ฒŒ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ƒ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋Œ€์ƒ์ด๋‹ค. "

์ธ์Šคํ„ด์Šค(instance)๋Š” ํด๋ž˜์Šค(class)๊ฐ€ Object(๊ฐ์ฒด)๋กœ ์„ ์–ธ๋˜๊ณ , ์„ ์–ธ๋˜์–ด์ง„ Object(๊ฐ์ฒด)๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น ๋˜์–ด ์‹ค์ œ ์‚ฌ์šฉ๋  ๋•Œ๊ฐ€ ๋ฐ”๋กœ ์ธ์Šคํ„ด์Šค(instance)์ด๋‹ค.

์ฆ‰, Object(๊ฐ์ฒด)๋ฅผ ์‹ค์ฒดํ™”ํ•œ ๊ฐœ๋…์ด๋‹ค

๐Ÿ”ฅ Instance ๊ด€์ ์—์„œ Class, Singleton, Static ์•Œ์•„๋ณด๊ธฐ

์•„๋ž˜์—์„œ ํด๋ž˜์Šค(class)์˜ ๊ธฐ๋Šฅ๋“ค์„ ์‚ดํŽด๋ณด๋ฉด์„œ, ์ธ์Šคํ„ด์Šค(instance)์— ๋Œ€ํ•œ ๋ถ€๋ถ„์€ ๊ณ„์†ํ•ด์„œ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๋‹ˆ, ๊ฐœ๋… ์ •๋„๋งŒ ์•Œ๊ณ  ์žˆ์œผ๋ฉด ๋œ๋‹ค.

์ž์„ธํ•˜๊ฒŒ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ๊ณต์œ ํ•œ ๊ธ€์„ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

Constructor

Class์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ์— ๋Œ€ํ•ด์„œ๋Š” ์•Œ์•„ ๋ดค์œผ๋‹ˆ, ์ด๋ฒˆ์—” constructor์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

Constructor๋Š” ์ƒ์„ฑ์ž๋ผ๊ณ  ํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ƒ์„ฑ์ž๋Š” ๋ฌด์—‡์ผ๊นŒ ?

ํด๋ž˜์Šค(class)๋Š” ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ํ•œ ๊ฐœ์˜ ์ƒ์„ฑ์ž ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ƒ์„ฑ์ž๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ƒ์„ฑ์ž๋Š” " ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ์— ํ˜ธ์ถœ๋˜๋Š” '์ธ์Šคํ„ด์Šค ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ' "์ด๋‹ค.

๋จผ์ €, ์ƒ์„ฑ์ž(constructor)์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด์ž.

์ฒ˜์Œ์— class์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ๋ฐฐ์šธ ๋•Œ์— ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ณ€์ˆ˜์— ์ดˆ๊ธฐ ๊ฐ’์„ ์ƒ์„ฑํ•˜์—ฌ ๋งŒ๋“ค์—ˆ์—ˆ๋‹ค.
์ด๋ฒˆ์—๋Š” ์ดˆ๊ธฐ ๊ฐ’ ์—†์ด constructor(์ƒ์„ฑ์ž)๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์คฌ๋‹ค.

์ด ๋‘˜์˜ ์ฐจ์ด์ ์€ ๋ญ˜๊นŒ ? ์™œ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ผ๊นŒ ?

class Person {
  final String name;
  
  const Person(this.name);
}

์ƒ์„ฑ์ž๊ฐ€ ์—†๋‹ค๋ฉด, ํด๋ž˜์Šค๋ฅผ ๊ฐ์ฒด๋กœ ์ธ์Šคํ„ด์Šคํ•  ๋•Œ์— ์ดˆ๊ธฐ ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ์ค„ ์ˆ˜๊ฐ€ ์—†๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, tyger์™€ alice๋ผ๋Š” ๋‘ ๊ฐœ์˜ Person ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด์ž. ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฐ์ฒด๋กœ ์ƒ์„ฑํ•œ ํ›„์— person.name์— ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

void main() {
  Person tyger = Person("tyger");
  print(tyger.name);
  
  // tyger
}

Default Constructor

class์—์„œ ์ƒ์„ฑ์ž๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ํ˜•ํƒœ์ด๋‹ค. ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค๋ช…๊ณผ ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Person ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ•  ๋•Œ์— name, age ๋ณ€์ˆ˜๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์„ฑ์ž์—์„œ ๋ณ€์ˆ˜์˜ ์ˆœ์„œ๋Œ€๋กœ ๊ผญ ๋„ฃ์„ ํ•„์š”๋Š” ์—†๋‹ค. ์ธ์Šคํ„ด์Šคํ•  ๋•Œ์—๋งŒ ์ƒ์„ฑ์ž์—์„œ ์ •์˜ํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

class Person {
  final String name;
  final int age;
  
  const Person(this.name, this.age);
}

// Person("tyger", 100);

์œ„์˜ ์ƒ์„ฑ์ž๋Š” ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„ ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋ฉด ์ˆœ์„œ๊ฐ€ ํ—ท๊ฐˆ๋ฆฌ๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— "Named"๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ƒ์„ฑ์ž๋Š” ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์—๋„ Argument๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์ด๋ฏ€๋กœ ์ต์ˆ™ํ•œ ๋‚ด์šฉ์ผ ๋“ฏ ํ•˜๋‹ค.

Named๋กœ ์ƒ์„ฑ์ž(constructor)๋ฅผ ์„ ์–ธํ•  ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ ์ค‘๊ด„ํ˜ธ "{}" ์•ˆ์—์„œ ๋“ฑ๋กํ•ด์•ผ ํ•˜๋ฉฐ, ํ•„์ˆ˜๋กœ ์ „๋‹ฌ ๋ฐ›์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋ผ๋ฉด required ํ‚ค์›Œ๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

class Person {
  final String name;
  final int age;
  
  const Person({
  	required this.name,
    required this.age,
  });
}

// Person(name: "tyger", age: 100);

ํ˜ผํ•ฉํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

class Person {
  final String name;
  final int age;

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

// Person("tyger", age: 100);

Named Constructor

์ด๋ฒˆ์—๋Š” ์ด๋ฆ„์žˆ๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๋„๋ก ํ•˜์ž.

์œ„์—์„œ Default Constructor์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋‹ค๋ฃฐ ๋•Œ์— ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค์˜ ์ด๋ฆ„๊ณผ ๋™์ผํ•˜๊ฒŒ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ–ˆ์—ˆ๋‹ค.

์ด๋ฆ„์ด ์žˆ๋Š” ์ƒ์„ฑ์ž๋กœ๋„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ƒ์„ฑ ๊ทœ์น™์€ ํด๋ž˜์Šค๋ช…์— ์ฉœ(.)์„ ์ž…๋ ฅํ•˜๊ณ  ์›ํ•˜๋Š” ์ƒ์„ฑ์ž ๋ช…์„ CamelCase ํ‘œ๊ธฐ๋ฒ•์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

" ์ƒ์„ฑ์ž๋Š” ํ•œ ๊ฐœ๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ƒ์„ฑ์ž๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. "

class Person {
  final String name;
  final int age;
  
  // Default
  const Person(this.name, this.age);
  
  // Named
  const Person.init(this.name, this.age);
}

// Person.init("tyger", 100);

์ƒ์„ฑ์ž๋Š” ์ด๋ฏธ ์ต์ˆ™ํ•œ ๋‚ด์šฉ์ด๋ผ class์˜ ๋‹ค๋ฅธ ๋‚ด์šฉ ๋“ค์„ ๋‹ค๋ฃจ๋ฉด์„œ ๋” ์ตํ˜€๋ณด๋„๋ก ํ•˜์ž.

Members

์œ„์—์„œ ํด๋ž˜์Šค๋ฅผ ์„ค๋ช…ํ•  ๋•Œ์— " class๋Š” ์†์„ฑ(attribute)๊ณผ ๋™์ž‘(behavior)์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์†์„ฑ์€ ๋ฉค๋ฒ„๋ณ€์ˆ˜(member variable), ๋™์ž‘์€ ๋ฉ”์„œ๋“œ(method)๋กœ ํ‘œํ˜„ ๋œ๋‹ค. " ๋ผ๊ณ  ํ–ˆ์—ˆ๋‹ค.

์†์„ฑ๊ณผ ๋™์ž‘์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

Method

๋ณ€์ˆ˜๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์•ž์„œ ๋™์ž‘๊ณผ ๊ด€๋ จ๋œ ํด๋ž˜์Šค ๋‚ด๋ถ€ ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž.

ํด๋ž˜์Šค๋Š” ๋‚ด๋ถ€์— Method๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Instance Method์™€ Static Method๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Person { 
  final String name;

  const Person(this.name);

  void printName() {
    print("My name is ${this.name}");
  }

  String returnName() => this.name;
}

Person ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ•œ ํ›„์— ๋‚ด๋ถ€ ํ•จ์ˆ˜์— ์ ‘๊ทผํ•˜์—ฌ ํ˜ธ์ถœํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

void main() {
  Person tyger = Person("Tyger");
  
  tyger.printName();
  // My name is Tyger
  
  print(tyger.returnName());
  // Tyger
}

์ถ”๊ฐ€๋กœ ์ •์  ๋ฉ”์„œ๋“œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Person {
  final String name;
  
  const Person(this.name);
  
  static void test(){
    print("Static Mehtod");
  }
}

// Person.test();
// Static Mehtod

Member Variable

" ํ•ด๋‹น ๊ธ€์€ ํด๋ž˜์Šค(class)์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ๋ณ€์ˆ˜์˜ ํƒ€์ž… ๋“ฑ์˜ ๊ด€ํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ์„œ ๋‹ค๋ฃจ์ง€ ์•Š์Œ "

์†์„ฑ์— ํ•ด๋‹นํ•˜๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜(MemberVaribale)์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

๋ฉค๋ฒ„ ๋ณ€์ˆ˜์—๋„ ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ Instance Varibale์™€ Static Varibale์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

์œ„์—์„œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ name ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑ ํ–ˆ์—ˆ๋‹ค. name์— ํ•ด๋‹นํ•˜๋Š” class์˜ ์†์„ฑ์„ ๋ณ€์ˆ˜(Varibale)๋ผ๊ณ  ํ•œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด Person ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์— name์€ ๊ธฐ๋ณธ ๊ฐ’์„ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒ์„ฑํ•œ ๋ณ€์ˆ˜์ด๊ณ , age๋Š” ๊ธฐ๋ณธ ๊ฐ’์„ 100์œผ๋กœ ์ฃผ์—ˆ๊ธฐ์— ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐํ™” ๋ณ€์ˆ˜์— ๋“ฑ๋กํ•˜์ง€ ์•Š์•„๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

class Person {
  final String name;
  int age = 100;
  
  Person(this.name);
}

abstract

ํด๋ž˜์Šค(class)์˜ ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์•Œ์•„๋ดค๋‹ค.

์›๋ž˜ ํด๋ž˜์Šค(class)์— ๋Œ€ํ•ด์„œ ๋ฐฐ์šธ ๋•Œ์—๋Š” ํด๋ž˜์Šค์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฐฐ์šฐ๊ณ , ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์ƒ์†์— ๋Œ€ํ•ด์„œ ๋ฐฐ์šฐ๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ƒ์†์„ ๋ฐฐ์šฐ๊ธฐ ์•ž์„œ ์ถ”์ƒ ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ ๋จผ์ € ๋ฐฐ์šฐ๊ณ  ๊ฐ€๋„๋ก ํ•˜๊ฒ ๋‹ค.

์™œ Abstract Class(์ถ”์ƒ ํด๋ž˜์Šค)๋ฅผ ๋จผ์ € ๋ฐฐ์›Œ์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์„ค๋ช… ํ•˜์ž๋ฉด, ์ƒ์†์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ๋ฐฐ์šธ ๋•Œ์— ๋ฐ˜๋“œ์‹œ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ์‚ฌ์ „ ์ง€์‹ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ์ถ”์ƒ ํด๋ž˜์Šค๋ผ๊ณ  ์ƒ๊ฐํ•ด์„œ ์ด๋‹ค.
๊ฐœ์ธ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์ ‘ํ–ˆ์„ ๋•Œ์— ์ถ”์ƒ ํด๋ž˜์Šค์˜ ๊ฐœ๋…์ด ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š๊ณ , ์ƒ์†์—์„œ ์ถ”์ƒ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋Š” ์—ญํ• ์— ๋Œ€ํ•ด์„œ ๋‚ฉ๋“์ด ๋˜์ง€ ์•Š์•˜์—ˆ๋‹ค.
์•Œ๊ณ  ๋ณด๋ฉด ์–ด๋ ต์ง€๋„ ์•Š๊ณ , ๊ฐ„๋‹จํ•œ ๊ฐœ๋…์ด๋‹ˆ ๋น ๋ฅด๊ฒŒ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž !

๊ทธ๋ ‡๋‹ค๋ฉด ์ถ”์ƒ(abstract) ํด๋ž˜์Šค๋Š” ๋ญ˜ ํ•˜๋Š” ๊ฑธ๊นŒ ?

"์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ฝ”๋“œ๋ฅผ ์ •์งํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์œ ํ˜•์„ ์•ˆ์ „ํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ตฌํ˜„ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์ถ”์ƒ ํด๋ž˜์Šค๊ฐ€ ์ •์˜ํ•˜๋Š” ๋ชจ๋“  ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋„๋ก ๋ณด์žฅ ํ•˜์ง€๋งŒ ๊ตฌํ˜„์€ ๊ฐ ํ•˜์œ„ ํด๋ž˜์Šค์— ๋งก๊น๋‹ˆ๋‹ค."

  • ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค
  • ์ธ์Šคํ„ด์Šค(instance)ํ•  ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค
  • ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” ์„ ์–ธ๋งŒ ๋˜๊ณ  ์ •์˜๋Š” ์—†๋Š” ๋ฉ”์„œ๋“œ

์ธ์Šคํ„ด์Šค(instance)ํ•  ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค๋ผ๋Š” ์˜๋ฏธ์— ๋Œ€ํ•ด์„œ๋Š” ์ด๋ฏธ ์œ„์—์„œ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•ด์„œ ์‚ดํŽด ๋ดค๊ธฐ ๋•Œ๋ฌธ์—, ๋ฌด์Šจ ์˜๋ฏธ์ธ์ง€ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค.
์ถ”์ƒ ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ์ด ๋˜๋ฉด, ๊ฐ์ฒด๋กœ ์ธ์Šคํ„ด์Šคํ™” ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค. ๋ฐ”๋กœ abstract ํ‚ค์›Œ๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด์ œ Person ํด๋ž˜์Šค๋Š” ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ์„ ์–ธ ๋ฌ๊ธฐ ๋•Œ๋ฌธ์—, ์ธ์Šคํ„ด์Šคํ•  ์ˆ˜ ์—†์–ด ๋‹จ๋…์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

abstract class Person {}

๋‹จ๋…์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๊ณ  ์ธ์Šคํ„ด์Šคํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์™œ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ๊นŒ ?

์ถ”์ƒ(abstract) ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชฉ์ ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ณตํ†ต๋œ ํŠน์ง•๊ณผ ๋™์ž‘์„ ์ถ”์ƒํ™”ํ•˜์—ฌ, ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹คํ˜•์„ฑ(polymorphism) ๋ฐ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’ํž ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๋œ๋‹ค.

Person ํด๋ž˜์Šค๋ฅผ introduce() ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ์ถ”์ƒ(abstract) ํด๋ž˜์Šค๋กœ ์ƒ์„ฑํ•˜์˜€๋‹ค.

introduce() ๋ฉ”์„œ๋“œ๋ฅผ ๋ณด๋ฉด ์„ ์–ธ์€ ๋˜์—ˆ์ง€๋งŒ ์ •์˜๋Š” ์—†๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ Person ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ •์˜ ๋ถ€๋ถ„์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

abstract class Person {
  void introduce();
}

์ถ”์ƒ(abstract) ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ๋Š” ์ด ์ •๋„๋งŒ ์•Œ๊ณ  ์žˆ์œผ๋ฉด, ์ƒ์†์„ ๋ฐฐ์šฐ๋Š” ๋ฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค.

์ƒ์†

์ด์ œ ์ด์–ด์„œ class์˜ ์ƒ์†์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

๋จผ์ € ์ƒ์†์€ ์™œ ํ•„์š”ํ• ๊นŒ ?

Flutter์—์„œ ์‚ฌ์šฉ๋˜๋Š” Dart ์–ธ์–ด๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ๋ฐ๋กœ ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์ด๋‹ค.

๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์—์„œ์˜ ์ƒ์†์€ ์ •๋ง ์ค‘์š”ํ•œ ๊ฐœ๋…์ด๋ฉฐ, ์ƒ์†์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ตฌ์กฐํ™”, ๋ชจ๋“ˆํ™” ๋ฐ ํ™•์žฅ์„ฑ์„ ๋†’ํ˜€์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ถ€๋ชจ๋‹˜์˜ ์žฌ์‚ฐ์„ ์ž์‹์—๊ฒŒ ๋ฌผ๋ ค์ฃผ๋Š” ๊ฒƒ์„ ์ƒ์†์ด๋ผ๊ณ  ํ•œ๋‹ค. Dart์—์„œ๋„ ๋™์ผํ•œ ๊ฐœ๋…์ด๋‹ค. ์ฆ‰, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์š”์†Œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.


์˜ˆ๋ฅผ ๋“ค์–ด, ์ž๋™์ฐจ์˜ ์—ฌ๋Ÿฌ ๋ชจ๋ธ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ์ž๋™์ฐจ์˜ ๋ชจ๋ธ์€ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์ŠคํŽ™์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒ ์ง€๋งŒ, ์ž๋™์ฐจ๋ผ๋Š” ๊ด€์ ์—์„œ๋Š” ์ž๋™์ฐจ ์ž์ฒด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ณ ์œ  ์†์„ฑ์€ ๋ชจ๋‘ ๋™์ผํ•  ๊ฒƒ์ด๋‹ค.

์ž๋™์ฐจ์˜ ๋ชจ๋ธ๋ณ„ ์ถœ๋ ฅ๊ณผ ๋งˆ๋ ฅ ์™ธ์—๋„ ๋งŽ์€ ์ŠคํŽ™์—์„œ๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์„ ๊ฒƒ์ด์ง€๋งŒ, ์ž๋™์ฐจ๋ผ๋Š” ๊ฒƒ์˜ ๋ชฉ์ ์—๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ์†์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค. ๋ฐ”ํ€ด๊ฐ€ 4๊ฐœ ๋ผ๋˜์ง€, ์ถœ๋ ฅ ๋˜๋Š” ํ† ํฌ๋ผ๋Š” ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋˜์ง€ .. ๋“ฑ๋“ฑ

์ด๋Ÿฐ ๋ถ€๋ถ„์„ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž๋™์ฐจ์˜ ์†์„ฑ์„ ๋‹ด๊ณ  ์žˆ๋Š” Car๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด, ๊ฐ ์ž๋™์ฐจ ๋ชจ๋ธ๋ณ„ Car ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๊ฒŒ ํ•˜๋ฉด ๊ณตํ†ต์ ์ธ ์†์„ฑ์— ๋Œ€ํ•ด ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์–ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ๋„ ๋†’์•„์ง€๊ณ , ๋ชจ๋“ˆํ™”๋ฅผ ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.


Flutter์—์„œ ์ƒ์† ๋ฐฉ๋ฒ•์€ ์ผ๋ฐ˜์ ์œผ๋กœ extends, implements, mixin ์ด๋ ‡๊ฒŒ 3๊ฐ€์ง€์˜ ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ ์ƒ์†๋ฐ›์•„ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด์ง€๋งŒ, ์ฐจ์ด๊ฐ€ ์žˆ์œผ๋‹ˆ ๊ฐ ์ฐจ์ด์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋ฉด์„œ ์ƒ์†์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

extends

์ฒซ ๋ฒˆ์งธ๋กœ extends ์ƒ์† ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์ƒ์†์—์„œ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜, ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž ์š”์†Œ๋ฅผ ๊ทธ๋Œ€๋กœ ์ƒ์† ๋ฐ›์•„์„œ ๊ตฌํ˜„ ์—†์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ•„์š”์— ๋”ฐ๋ผ ์žฌ์ •์˜ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Car ํด๋ž˜์Šค์— ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ name์„ ์„ ์–ธ ํ•ด์ฃผ๊ณ , ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๊ณ  printName() ์ด๋ผ๋Š” name์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ƒ์„ฑํ•ด ๋ณด์ž.

class Car {
  final String name;

  const Car(this.name);

  void printName() => print("์ž๋™์ฐจ ์ด๋ฆ„์€ $name ์ž…๋‹ˆ๋‹ค");
}

์ด์ œ G70์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Car ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋„๋ก ํ•ด์ฃผ์ž.

์ด๋ ‡๊ฒŒ ์ƒ์† ๋ฐ›๊ฒŒ ๋˜๋ฉด, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

class G70 extends Car {}

์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” Car ํด๋ž˜์Šค์—์„œ name์„ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ์ด๋‹ค.

Car ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์ดˆ๊ธฐํ™” ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค (์ƒ์„ฑ์ž๊ฐ€ ์—†๋‹ค๋ฉด ์ƒ๊ด€์—†๋‹ค)

class G70 extends Car {
  const G70(super.name);
}

์ด์ œ G70 ํด๋ž˜์Šค๊ฐ€ Car ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•˜๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์ž. ์ •์ƒ์ ์œผ๋กœ ์ƒ์†์„ ๋ฐ›์•˜๋‹ค.

void main() {
  final G70 g70 = G70("G70");
  g70.printName();
  // ์ž๋™์ฐจ ์ด๋ฆ„์€ G70 ์ž…๋‹ˆ๋‹ค
}

Car ํด๋ž˜์Šค๋กœ ๋ถ€ํ„ฐ ์ƒ์† ๋ฐ›์€ ๋ฉ”์„œ๋“œ์ธ printName()์˜ ์ถœ๋ ฅ ๋ฌธ๊ตฌ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์–ด์กŒ๋‹ค. ์ด๋Ÿด ๋•Œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ๋งŒ ํ•˜๋Š” ๊ฑธ๊นŒ ?

๊ทธ๋Ÿด ํ•„์š” ์—†๋‹ค. ์žฌ์ •์˜(override) ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์žฌ์ •์˜(override)๋Š” Dart annotation ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ๋กœ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๋‹ค์‹œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์žฌ์ •์˜(override)์— ๋Œ€ํ•ด์„œ๋Š” ์ด๋ฏธ ์ต์ˆ™ํ•˜๊ฒŒ ์ž์ฃผ ๋ดค์„ ๊ฒƒ์ด๋‹ค. StatelessWidget์˜ build ๋ถ€๋ถ„์˜ ์žฌ์ •์˜๊ฐ€ ๋ฐ”๋กœ build๋ฅผ ๋‹ค์‹œ ์ •์˜ ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

์žฌ์ •์˜(override)ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ์‹ฌํ”Œํ•˜๋‹ค. ๋ฐ”๋กœ "@override" annotation์„ ์ถ”๊ฐ€ํ•ด ์ค€ ๋’ค, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋‹ค์‹œ ์ •์˜ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

class G70 extends Car {
  const G70(super.name);

  
  void printName() => print("$name ์ž…๋‹ˆ๋‹ค");
}

์ด์ œ ๋‹ค์‹œ ์ถœ๋ ฅํ•ด๋ณด๋ฉด, ์žฌ์ •์˜๋œ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๊ถ๊ธˆํ•˜์‹ค ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ด ๋ฐ”๋กœ "@override" annotation์„ ๊ผญ ๋„ฃ์–ด์ค˜์–ด์•ผ ํ•˜๋Š” ๊ฑด์ง€์— ๋Œ€ํ•ด์„œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์‚ฌ์‹ค annotation์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ์žฌ์ •์˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ Dart ์–ธ์–ด์˜ ๋ฌธ๋ฒ•์ด์ž ๊ทœ์น™์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐœ๋ฐœ์ž๋“ค์€ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ์ฃผ์„๋ฌธ์ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•œ ๊ฒƒ์ธ๊ฐ€๋ฅผ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ˜๋“œ์‹œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๋Š” ์Šต๊ด€์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.

"annotation์€ ์‚ฌ์ „์  ์˜๋ฏธ๋กœ๋Š” ์ฃผ์„์ด์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ์„์ด ์•„๋‹Œ ํ”„๋กœ๊ทธ๋žจ์—๊ฒŒ ์ถ”๊ฐ€์ ์ธ ์ •๋ณด์ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(metadata)๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ํ•˜๋Š” ๋ฌธ๋ฒ•"

G80 ํด๋ž˜์Šค๋„ Car ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„ ์ƒ์„ฑํ•ด์ฃผ์ž.

class G80 extends Car {
  const G80(super.name);
}

G80 ํด๋ž˜์Šค๋Š” ์žฌ์ •์˜ ํ•ด์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์ถœ๋ ฅ์ด ๋œ๋‹ค.

void main() {
  final G70 g70 = G70("G70");
  final G80 g80 = G80("G80");
  g70.printName();
  // G70 ์ž…๋‹ˆ๋‹ค

  g80.printName();
  // ์ž๋™์ฐจ ์ด๋ฆ„์€ G80 ์ž…๋‹ˆ๋‹ค
}

Car ํด๋ž˜์Šค์— ์ •์ˆ˜ํ˜• ๋ฉค๋ฒ„๋ณ€์ˆ˜ hp๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๊ณ , getHorsePower() ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ƒ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

class Car {
  final int hp;
  final String name;

  const Car(this.name, this.hp);

  void getHorsePower() => print("$name ๋งˆ๋ ฅ : $hp");
}

์ด์ œ ๊ธฐ์กด G70, G80 ํด๋ž˜์Šค์—์„œ๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ผ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ณด์ผ ๊ฒƒ์ด๋‹ค. hp๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜์—ฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด๋ฒˆ์—๋Š” ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)๋ฅผ ์ธ์Šคํ„ด์Šคํ•  ๋•Œ์— ์ƒ์„ฑ์ž(constructor)๋ฅผ ํ†ตํ•ด์„œ ์ดˆ๊ธฐํ™” ๊ฐ’์„ ๋ฐ›์•„์˜ค์ง€ ์•Š๊ณ , ์ดˆ๊ธฐํ™” ๊ฐ’์„ ๋‚ด๋ถ€์— ์„ ์–ธํ•˜์—ฌ ์ธ์Šคํ„ด์Šค์‹œ ๊ฐ’์„ ๋ฐ›์•„์™€๋„ ๋˜๊ณ  ๋ฐ›์•„์˜ค์ง€ ์•Š์•„๋„ ๋  ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋„๋ก ํ•˜์ž.

์ผ๋ฐ˜์ ์œผ๋กœ ํด๋ž˜์Šค์—์„œ ์ƒ์„ฑ์ž(constructor)์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ต์…”๋„๋กœ ๋„ฃ์œผ๋ ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

class Test {
  final String name;
  const Test({this.name = ""});
}

ํ•˜์ง€๋งŒ G70 ํด๋ž˜์Šค์—์„œ ์ƒ์„ฑ์ž(constructor)๋ฅผ ์˜ต์…”๋„ํ•˜๊ฒŒ ๋„ฃ์œผ๋ ค๊ณ  ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ทธ ์ด์œ ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์ƒ์„ฑ์ž์—๋Š” ๊ธฐ๋ณธ ๊ฐ’ ์—†์ด ์ƒ์„ฑ์ž๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ƒ์† ๋ฐ›์€ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)๋„ ์ƒ์„ฑ์ž์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ต์…”๋„ํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์ƒ์„ฑ์ž๋ฅผ ์˜ต์…”๋„๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ๊ณ , ๋Œ€์‹  ๊ธฐ๋ณธ ๊ฐ’์„ ๋ฐ˜๋“œ์‹œ ๋„ฃ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ๊ฐ’์„ ์ƒ์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

class Car {
  final int hp;
  final String name;

  const Car({this.name = "", this.hp = 0});

  void getHorsePower() => print("$name ๋งˆ๋ ฅ : $hp");
}

์ด์ œ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ์ƒ์„ฑ์ž(constructor)๋Š” ์„ ํƒ ์‚ฌํ•ญ์ด ๋˜๋ฏ€๋กœ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด๋„ ๋˜๊ณ  ์—†์–ด๋„ ๋œ๋‹ค.

G80 ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž ์•ˆ์—์„œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์˜ต์…”๋„ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

class G80 extends Car {
  const G80({super.name = "G80", super.hp = 250});
}

์ด์ œ G80 ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ•  ๋•Œ์— Default ์ƒ์„ฑ์ž๋ฅผ ์˜ต์…”๋„ํ•˜๊ฒŒ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

void main() {
  G80 g80 = G80();
  g80.getHorsePower();
  // G80 ๋งˆ๋ ฅ : 250
}

์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

G80 ๋ชจ๋ธ์—๋Š” ์„ธ๋‹จํ˜• ํƒ€์ž…์˜ ๋ชจ๋ธ๋งŒ ์žˆ์ง€๋งŒ, G70 ๋ชจ๋ธ์—๋Š” ์„ธ๋‹จํ˜•๊ณผ ์™œ๊ฑดํ˜• ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ๋ชจ๋ธ์ด ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด subName์ด๋ผ๋Š” ๋ฌธ์ž์—ด ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ Car ํด๋ž˜์Šค์— ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”๊ฒŒ ๋งž์„๊นŒ ? ์•„๋‹ˆ๋‹ค.

G80 ๋ชจ๋ธ์—๋Š” ํ•„์š”๊ฐ€ ์—†๊ณ , G70 ๋ชจ๋ธ์—๋งŒ subName ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์ธ Car ํด๋ž˜์Šค์— ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์ธ G70 ํด๋ž˜์Šค์—๋งŒ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋งž๋‹ค.

class G70 extends Car {
  final String subName;
}

๋ฉค๋ฒ„๋ณ€์ˆ˜ subName๋„ ์ƒ์„ฑ์ž(constructor)๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™” ํ•ด์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

๊ธฐ๋ณธ ์ดˆ๊ธฐํ™” ๊ฐ’์„ ์ฃผ์ง€ ์•Š์•˜๊ธฐ์— required๋ฅผ ์‚ฌ์šฉํ•ด ํ•„์ˆ˜๋กœ ์ธ์Šคํ„ด์Šค์‹œ ๊ฐ’์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ๋‹ค.

๊ธฐ์กด ํด๋ž˜์Šค ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

class G70 extends Car {
  final String subName;
  
  const G70({
    super.name = "G70",
    super.hp = 230,
    required this.subName,
  });
}

์—ฌ๊ธฐ์„œ super?, this? ์˜ ๊ถ๊ธˆ์ค‘์ด ์ƒ๊ฒผ์„๊ฑฐ๋‹ค. ์ฐจ์ด์ ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

super์™€ this๋Š” ๊ฐ„๋‹จํ•œ ๋ฌธ๋ฒ•์ด๋‹ค.

this๋ž€ ํ˜„์žฌ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ž€ ์˜๋ฏธ์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ํ˜„์žฌ ํด๋ž˜์Šค์ธ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์ง€์ •์„ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.

super๋Š” ์ƒ์† ๋ฐ›์€ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.

Dart ์–ธ์–ด์—์„œ๋Š” super ํ‚ค์›Œ๋“œ ์—†์ด ์‚ฌ์šฉ์‹œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์—์„œ ์ƒ์† ๋ฐ›์€ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜์ง€๋งŒ, this์˜ ์˜ํ–ฅ์œผ๋กœ ์ธํ•˜์—ฌ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์žฌ์ •์˜ ๋˜์—ˆ๋‹ค๋ฉด ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค.

Person ํด๋ž˜์Šค๋ฅผ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ name์„ ์ถ”๊ฐ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์ž.

class Person {
  final String name = "Empty";
}

Tyger ํด๋ž˜์Šค๋Š” Person ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋„๋ก ํ•ด์ฃผ๊ณ , Tyger ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ name์„ ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

super.name์€ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์ธ Person ํด๋ž˜์Šค์˜ name์ด๋‹ค. this ํ‚ค์›Œ๋“œ๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

class Tyger extends Person {
  final String name = "Tyger";

  void log() => print("Person name: ${super.name}, Tyger name: ${this.name}");
}

Tyger ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ•˜๊ณ , log() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ๋ณด์ž.

void main() {
  Tyger tyger = Tyger();
  tyger.log();
  // Person name: Empty, Tyger name: Tyger
}

super, this ๊ธฐ๋Šฅ๋„ ๋” ์ฐพ์•„๋ณด๋ฉด ๊นŠ๊ฒŒ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š” ๋‚ด์šฉ์ด ๋งŽ์ง€๋งŒ ํฌ๊ฒŒ ๊ฐœ๋…์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด์„œ๋งŒ ์•Œ๊ณ  ์žˆ์œผ๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๋””ํ…Œ์ผํ•˜๊ฒŒ ์•Œ๊ณ  ์‹ถ์œผ์‹  ๋ถ„๋“ค์€ ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ๋ณ„๋„๋กœ ์ž‘์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

implements

์ง€๊ธˆ๊นŒ์ง€ ์ƒ์† ํ‚ค์›Œ๋“œ ์ค‘ extends์— ๋Œ€ํ•ด์„œ ๋ฐฐ์›Œ๋ดค๋‹ค.

์•„์ง ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์œผ๋‚˜, ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋ฉด์„œ ๋” ์•Œ์•„๊ฐ€ ๋ณด๋„๋ก ํ•˜์ž.

์ด๋ฒˆ์— ๋ฐฐ์šฐ๊ฒŒ ๋  ์ƒ์† ๋ฐ›๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ธ implements์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

implements ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์†์—์„œ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜, ๋ฉ”์„œ๋“œ ๋“ฑ์˜ ์š”์†Œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ํ•„์ˆ˜์ ์œผ๋กœ ๋ชจ๋‘ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์† ๋ฐฉ๋ฒ•์ด๋‹ค.

์ฐจ์ด์ ์„ ๋ณด์ž๋ฉด extends ์ƒ์†์€ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์ƒ์†์‹œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์š”์†Œ๋ฅผ ๊ตฌํ˜„ํ•  ํ•„์š” ์—†์ด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ ๋ฐ˜๋ฉด, implements ์ƒ์†์€ ์ƒ์† ๋ฐ›์€ ์š”์†Œ๋ฅผ ํ•„์ˆ˜์ ์œผ๋กœ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋ถ€๋ถ„์—์„œ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์ด ์žˆ๋‹ค.

์œ„์˜ ์„ค๋ช…์ด ์‰ฝ๊ฒŒ ์ดํ•ด๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ, ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์„œ ํ™•์ธํ•ด ๋ณด๋„๋ก ํ•˜์ž.

Test ํด๋ž˜์Šค๋ฅผ log()๋ผ๋Š” ๋ฉ”์„œ๋“œ๋งŒ ์ถ”๊ฐ€ํ•˜์—ฌ ์ƒ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

class Test {
  void log() => print("Test !!");
}

extends

๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค) Test๋ฅผ extends ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ์† ๋ฐ›๋Š” TestExtends ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์ž.

ํฐ ๋ฌธ์ œ ์—†์ด ์ž˜ ์ƒ์„ฑ์ด ๋˜์—ˆ๋‹ค.

class TestExtends extends Test {}

implements

์ด๋ฒˆ์—๋„ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค) Test๋ฅผ implements ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ์† ๋ฐ›๋Š” TestImplements ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์˜€๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. TestImplements์— ์—๋Ÿฌ ๋ผ์ธ์ด ํ‘œ์‹œ๋˜์—ˆ๋‹ค.

class TestImplements implements Test {}

์—๋Ÿฌ ๋ถ€๋ถ„์—์„œ ๋น ๋ฅธ ์ˆ˜์ • ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๋ณด๋ฉด "Create 1 missing override" ๋ผ๋Š” ์ˆ˜์ •์ด ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์ˆ˜์ •์„ ํ•ด๋ณด๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ log() ๋ฉ”์„œ๋“œ๋ฅผ override ํ•˜๋ผ๊ณ  ๋‚˜์˜จ๋‹ค.


void log() {
	// TODO: implement log
}

์œ„์—์„œ implements ์ƒ์† ๋ฐฉ๋ฒ•์—์„œ ์„ค๋ช…ํ•œ "๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜, ๋ฉ”์„œ๋“œ ๋“ฑ์˜ ์š”์†Œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ํ•„์ˆ˜์ ์œผ๋กœ ๋ชจ๋‘ ๊ตฌํ˜„" ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ •์˜ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ƒ์„ฑ์ž๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์žฌ์ •์˜(override) ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์† ๋ฐฉ๋ฒ•์ด๋‹ค.

์šฐ์„  implements๋ฅผ ์‚ฌ์šฉํ•œ ์ƒ์†์„ ์ตํ˜€๋ณด๋„๋ก ํ•˜์ž.

Car ํด๋ž˜์Šค์— getHorsePower() ๋ผ๋Š” ์ž๋™์ฐจ ๋ชจ๋ธ์˜ ๋งˆ๋ ฅ์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–์—ฌ ์ƒ์„ฑํ•ด ์ฃผ์ž.

class Car {
  void getHorsePower(int hp) => print("๋งˆ๋ ฅ์€ $hp ์ž…๋‹ˆ๋‹ค.");
}

Car ํด๋ž˜์Šค๋ฅผ implements๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์†๋ฐ›๋Š” G70 ํด๋ž˜์Šค๋ฅด ๋งŒ๋“ค์–ด ์ฃผ์ž.

์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์žฌ์ •์˜(override)ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์šฐ์„  ์•„๋ฌด๊ฒƒ๋„ ์ž‘์„ฑํ•˜์ง€ ์•Š๋„๋ก ํ•˜์ž.

class G70 implements Car {
  
  void getHorsePower(int hp) {}
}

G70 ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ•œ ํ›„์— getHorsePower ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด๋ณด์ž.

๋‹น์—ฐํžˆ ๊ฒฐ๊ณผ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

void main() {
  G70 g70 = G70();
  g70.getHorsePower(250);
}

๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ƒ์† ๋ฐ›์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

๋ฌธ์ž์—ด name ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์ž.

class Car {
  final String name;
  const Car(this.name);
  void getHorsePower(int hp) => print("๋งˆ๋ ฅ์€ $hp ์ž…๋‹ˆ๋‹ค.");
}

๋ฉค๋ฒ„๋ณ€์ˆ˜๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์žฌ์ •์˜(override) ํ•ด์•ผ ํ•œ๋‹ค.

class G70 implements Car {
  
  String get name => "G70";
  
  
  void getHorsePower(int hp) {}
}

์ด์ฏค ๋˜๋ฉด ๋„๋Œ€์ฒด ์™œ implements ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ๊นŒ ? ๊ทธ๋ƒฅ extends ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€ ?

์—ฌ๊ธฐ์„œ ๋ฐ”๋กœ ์‚ฌ์ „ ์ง€์‹์œผ๋กœ ์‚ดํŽด๋ณธ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด, ์™œ implements ์ƒ์†์„ ์‚ฌ์šฉ ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜น์‹œ๋ผ๋„ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ ๋ชจ๋ฅด์‹œ๊ฑฐ๋‚˜ ์œ„์— ์ž‘์„ฑ๋œ ๊ธ€์„ ๋ณด์ง€ ์•Š์œผ์‹  ๋ถ„์€ ํ•œ ๋ฒˆ์€ ๋ณด์‹œ๊ธธ ์ถ”์ฒœ ํ•ฉ๋‹ˆ๋‹ค.
์•„์ง ์™„์ „ํžˆ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋”๋ผ๋„ ๊ฑฑ์ •ํ•˜์ง€ ์•Š์œผ์…”๋„ ๋œ๋‹ค.

์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋Š” ์•ž์„œ ์„ค๋ช… ํ–ˆ๋“ฏ์ด ๋‹จ๋…์ ์œผ๋กœ๋Š” ์ธ์Šคํ„ด์Šค(instance) ํ•  ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค์ด๋ฉฐ, ์„ ์–ธ๋งŒ ๋˜๊ณ  ์ •์˜๋Š” ์—†๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ–ˆ์—ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ ๋ฐ”๋กœ "์ •์˜๋Š” ์—†๋Š” ๋ฉ”์„œ๋“œ" ๋ผ๋Š” ๋ถ€๋ถ„์ด๋‹ค. ์ด ๋ง์˜ ์˜๋ฏธ๋Š” ์„ ์–ธ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

implements ์ƒ์†์„ ๋ณด๋ฉด, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์—์„œ ์„ ์–ธํ•˜๊ณ  ์ •์˜๋ฅผ ํ•ด๋„ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ํ•„์ˆ˜์ ์œผ๋กœ ์žฌ์ •์˜(override) ํ•ด์•ผ ๋˜๋Š” ๋ถ€๋ถ„์ด ์™œ implements ์ƒ์†์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ์˜๋ฌธ์ด์—ˆ๋˜ ๋ถ€๋ถ„์ด๋‹ค.

์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ ์–ธ๋งŒ ํ•˜๋ฉด ๋˜๊ณ  implements ์ƒ์† ํ›„์— ์ •์˜๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

Car ํด๋ž˜์Šค๋ฅผ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋กœ ์ƒ์„ฑํ•˜๊ณ  getHorsePower ๋ฉ”์„œ๋“œ๋„ ์„ ์–ธ๋งŒ ํ•ด์ฃผ๋„๋ก ํ•˜์ž.

abstract class Car {
  void getHorsePower(int hp);
}

์ด์ œ G70 ํด๋ž˜์Šค์—์„œ Car ํด๋ž˜์Šค๋ฅผ implements ์ƒ์†์„ ์‚ฌ์šฉํ•ด ์ƒ์† ๋ฐ›๋„๋ก ํ•˜์ž.

์ƒ์† ๋ฐ›์€ G70 ํด๋ž˜์Šค์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค. ๊ฐ„๋‹จํ•˜๋‹ค.

class G70 implements Car {
  
  void getHorsePower(int hp) => print("๋งˆ๋ ฅ์€ $hp");
}

์žฌ์ •์˜(override)ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰์ด ๋œ๋‹ค.

void main() {
  G70 g70 = G70();
  g70.getHorsePower(250);
  // ๋งˆ๋ ฅ์€ 250
}

์ด๋ฒˆ์—๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค์— ์„ ์–ธํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

์šฐ์„  ์ถ”์ƒ(abstract)ํด๋ž˜์Šค์•ˆ์—์„œ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ์„ ์–ธํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ๋‹ค์–‘ํ•˜๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” Getter๋ฅผ ์‚ฌ์šฉํ•ด ์„ ์–ธํ•ด ์ค€๋‹ค.

๋ฉค๋ฒ„๋ณ€์ˆ˜๋„ ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ ์„ ์–ธ๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์ •์˜๋Š” ํ•„์š” ์—†๋‹ค.

abstract class Car {
  String get name;
}

G70 ํด๋ž˜์Šค์—์„œ๋„ Getter๋ฅผ ์‚ฌ์šฉํ•œ ์ •์˜๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค.

class G70 implements Car {
  final String _name;
  const G70(this._name);

  
  String get name => _name;
}

์ง€๊ธˆ๊นŒ์ง€ ์ƒ์† ๋ฐฉ๋ฒ• ์ค‘ extends, implements ์ƒ์† ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„ ๋ดค๋‹ค.

๋™์ผํ•œ ์ƒ์† ๊ธฐ๋Šฅ์ด๋ผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ์‚ฌ์‹ค ์ „ํ˜€ ๋‹ค๋ฅธ ์ƒ์† ๋ฐฉ๋ฒ•์ธ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ๊ถ๊ธˆ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ extends ์ƒ์†ํ•˜๊ฒŒ ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

์ถ”์ƒ(abstract)ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์˜๊ฐ€ ๋œ ์ƒํƒœ๋ผ๋ฉด extends ์ƒ์†์„ ํ•ด๋„ ์žฌ์ •์˜(override) ํ•  ํ•„์š”๊ฐ€ ์—†์ง€๋งŒ, ์ •์˜๊ฐ€ ๋˜์ง€ ์•Š๊ณ  ์„ ์–ธ๋งŒ ๋˜์—ˆ๋‹ค๋ฉด extends ๋ฐฉ๋ฒ•๋„ implements ์ƒ์†๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์žฌ์ •์˜(override) ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

abstract class Person {
  void printName(String name);
}

์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์žฌ์ •์˜(override)ํ•ด์•ผ ํ•œ๋‹ค.

class Tyger extends Person {
  
  void printName(String name) => print("์ด๋ฆ„์€ Tyger !");
}

์•„์ง ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํด๋ž˜์Šค๋ฅผ ๊ตฌ์ถ•ํ•˜๋‹ค ๋ณด๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ตํ˜€์ง€๋Š” ๋ถ€๋ถ„์ด๋‹ˆ ์ฒœ์ฒœํžˆ ๋ฐฐ์›Œ๊ฐ€๋ฉด ๋œ๋‹ค.

extends ์ƒ์†์€ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜, ๋ฉ”์†Œ๋“œ ๋“ฑ์˜ ์š”์†Œ๋ฅผ ์ „๋ถ€ ์ƒ์† ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ˜๋ฉด implements ์ƒ์†์€ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค) ์—์„œ ์žฌ์ •์˜(override)ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.


Example

extends, implements ์ค‘ ์–ด๋–ค ์ƒ์† ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์ข€ ๋” ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

์Šˆํผ ํžˆ์–ด๋กœ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

์Šˆํผ ํžˆ์–ด๋กœํ•œํ…Œ๋Š” ๊ณต๊ฒฉ๋ ฅ๊ณผ ๋ฐฉ์–ด๋ ฅ์„ ๋‚˜ํƒ€๋‚ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.

๋งˆ๋ธ” ํžˆ์–ด๋กœ์—๊ฒŒ๋Š” tier ๋ผ๋Š” ๋“ฑ๊ธ‰์„ ๊ฐ–๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค. tier๋Š” 1~9๊นŒ์ง€์˜ ์ˆœ์„œ๋กœ 1์ด ๊ฐ€์žฅ ๋†’์€ ๋“ฑ๊ธ‰์ธ๋ฐ, ๊ณต๊ฒฉ๋ ฅ์ด๋ผ๋Š” getAttack ๋ฉ”์„œ๋“œ๋Š” 10์—์„œ tier๋ฅผ ๋นผ์ค€ ๊ฐ’์— ๊ณฑํ•˜๊ธฐ 100์„ ํ•ด์ฃผ๊ณ  ๋ฐฉ์–ด๋ ฅ์€ 20์„ ๊ณฑํ•ด์ฃผ๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

class Hero {
  final String name;
  final int tier;
  const Hero({
    required this.tier,
    required this.name,
  });

  int getAttack() => (10 - tier) * 100;
  int getDefence() => (10 - tier) * 20;
}

์ด์ œ ๋งˆ๋ธ” ํžˆ์–ด๋กœ์ธ ์•„์ด์–ธ๋งจ๊ณผ ํ—ํฌ์˜ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ธ๋ฐ, Hero ํด๋ž˜์Šค๋ฅผ extends ์ƒ์†์„ ๋ฐ›๋„๋ก ํ•˜๊ฒ ๋‹ค.

์•„์ด์–ธ๋งจ์˜ tier๋Š” 9๋“ฑ๊ธ‰ ์ด๊ณ , ํ—ํฌ์˜ tier๋Š” 7๋“ฑ๊ธ‰์œผ๋กœ ํ•ด์ฃผ์—ˆ๋‹ค.

class IronMan extends Hero {
  const IronMan({super.tier = 9, super.name = "IronMan"});
}

class Hulk extends Hero {
  final String name = "Hulk";
  const Hulk({super.tier = 7, super.name = "Hulk"});
}

์ด์ œ ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šค(instance)ํ•œ ํ›„์— ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ฃผ์ž.

void main() {
  IronMan ironMan = IronMan();
  Hulk hulk = Hulk();
  print(
      "${ironMan.name}์˜ ๊ณต๊ฒฉ๋ ฅ์€ ${ironMan.getAttack()}, ๋ฐฉ์–ด๋ ฅ์€ ${ironMan.getDefence()}์ด๋‹ค.");
  // IronMan์˜ ๊ณต๊ฒฉ๋ ฅ์€ 100, ๋ฐฉ์–ด๋ ฅ์€ 20์ด๋‹ค.

  print("${hulk.name}์˜ ๊ณต๊ฒฉ๋ ฅ์€ ${hulk.getAttack()}, ๋ฐฉ์–ด๋ ฅ์€ ${hulk.getDefence()}์ด๋‹ค.");
  // Hulk์˜ ๊ณต๊ฒฉ๋ ฅ์€ 300, ๋ฐฉ์–ด๋ ฅ์€ 60์ด๋‹ค.
}

extends ์ƒ์†์„ ์‚ฌ์šฉํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์—ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. DC ํžˆ์–ด๋กœ๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€ ๋˜์—ˆ๋Š”๋ฐ, DC ํžˆ์–ด๋กœ๋Š” tier๋ผ๋Š” ๋“ฑ๊ธ‰์ด ์—†๋Š” ์ƒํƒœ์ด๋ฉฐ, ๊ณต๊ฒฉ๋ ฅ๊ณผ ๋ฐฉ์–ด๋ ฅ์„ ๊ณ„์‚ฐํ•˜๋Š” ์‹์ด ๋งˆ๋ธ” ํžˆ์–ด๋กœ์™€ ๋‹ค๋ฅด๋‹ค.

ํ•˜์ง€๋งŒ ๊ณต๊ฒฉ๋ ฅ๊ณผ ๋ฐฉ์–ด๋ ฅ์€ ๋งˆ๋ธ” ํžˆ์–ด๋กœ, DC ํžˆ์–ด๋กœ ๋ชจ๋‘์—๊ฒŒ ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ์ด๋‹ค.

์ž ์ด๋Ÿด ๊ฒฝ์šฐ extends ์ƒ์†์ด ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ผ๊นŒ ? ํด๋ž˜์Šค์˜ ์š”์†Œ๋ฅผ ๊ฐ•์ œํ•˜๊ณ  ์‹ถ์€๋ฐ, ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์ „๋ถ€ ์žฌ์ •์˜ ํ•˜๊ฒŒ ํ•ด์•ผํ•  ๊ฒƒ์ด๋‹ค.

์ด๋ ‡ ๋•Œ์— implements ์ƒ์†์œผ๋กœ ๊ตฌํ˜„ํ•ด ๋ณด๋„๋ก ํ•˜์ž.

Hero ํด๋ž˜์Šค์—์„œ name ๋ณ€์ˆ˜์™€ getAttack, getDefence๋ฅผ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ ์ถ”์ƒํ™”ํ•˜์—ฌ ์„ ์–ธ๋งŒ ํ•˜์˜€๋‹ค.
์ด๋ ‡๊ฒŒ ๋˜๋ฉด Hero๋ฅผ ์ƒ์† ๋ฐ›๋Š” ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ๋Š” Hero์˜ ํด๋ž˜์Šค ์š”์†Œ๋ฅผ ์ „๋ถ€ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

abstract class Hero {
  final String name;
  const Hero(this.name);

  int getAttack();
  int getDefence();
}

์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ ธ ์•„์ด์–ธ๋งจ๊ณผ ์Šˆํผ๋งจ๋งŒ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์˜€๋‹ค.

class IronMan implements Hero {
  final int tier = 9;
  
  int getAttack() => (10 - tier) * 100;

  
  int getDefence() => (10 - tier) * 20;

  
  String get name => "IronMan";
}

class SuperMan implements Hero {
  
  int getAttack() => 1000;

  
  int getDefence() => 100;

  
  String get name => "SuperMan";
}

์ด์ œ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ด ๋ณด๋„๋ก ํ•˜์ž.

void main() {
  IronMan ironMan = IronMan();
  SuperMan superMan = SuperMan();
  print(
      "${ironMan.name}์˜ ๊ณต๊ฒฉ๋ ฅ์€ ${ironMan.getAttack()}, ๋ฐฉ์–ด๋ ฅ์€ ${ironMan.getDefence()}์ด๋‹ค.");
  // IronMan์˜ ๊ณต๊ฒฉ๋ ฅ์€ 100, ๋ฐฉ์–ด๋ ฅ์€ 20์ด๋‹ค.
  
  print(
      "${superMan.name}์˜ ๊ณต๊ฒฉ๋ ฅ์€ ${superMan.getAttack()}, ๋ฐฉ์–ด๋ ฅ์€ ${superMan.getDefence()}์ด๋‹ค.");
  // SuperMan์˜ ๊ณต๊ฒฉ๋ ฅ์€ 1000, ๋ฐฉ์–ด๋ ฅ์€ 100์ด๋‹ค.
}

์ด์ œ extends, implements ์ƒ์†์— ๋Œ€ํ•ด์„œ๋Š” ์ดํ•ดํ–ˆ์„ ๊ฑฐ๋ผ ์ƒ๊ฐํ•œ๋‹ค.

์œ„์˜ ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด, ์•„์ง๋„ ๋ญ”๊ฐ€ ๋ถ€์กฑํ•œ ๋Š๋‚Œ์ด๊ณ  ๋ถˆํŽธํ•˜๋‹ค. ๋งˆ๋ธ” ํžˆ์–ด๋กœ์ธ ๊ฒฝ์šฐ๋Š” tier๊ฐ€ ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•˜๋Š”๋ฐ, DC ํžˆ์–ด๋กœ์˜ tier๊ฐ€ ์—†๋‹ค๋Š” ์ด์œ  ๋•Œ๋ฌธ์—, ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ tier ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•˜๊ณ , ์ด๋Ÿฌํ•œ ํด๋ž˜์Šค๊ฐ€ 100๊ฐœ 1000๊ฐœ๊ฐ€ ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๋ฉด ๋„ˆ๋ฌด ๊ท€์ฐฎ์€ ์ผ์ด ๋ฐœ์ƒํ•œ๋‹ค.

์—ฌ๋Ÿฌ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์—†์„๊นŒ ?

๋‹ค์ค‘์ƒ์†

์ด์ œ ๋ถ€ํ„ฐ ํ•œ ๊ฐœ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ ์ƒ์† ๋ฐ›๋Š” ๋‹ค์ค‘์ƒ์†์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Dart ์–ธ์–ด๊ฐ€ ๊ฐ์ฒด์ง€ํ–ฅ์–ธ์–ด(OOP)๋ผ๋Š” ๊ฒƒ์€ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” ๋‚ด์šฉ์ด๋‹ค. ๊ฐ์ฒด์ง€ํ–ฅ์–ธ์–ด์˜ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์ธ๋ฐ, ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ํด๋ž˜์Šค(class)๋ฅผ ๋‹ค์ค‘์œผ๋กœ ์ƒ์† ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
ํ•˜์ง€๋งŒ ๋Œ€์ฒด์ ์œผ๋กœ OOP์—์„  ๋‹ค์ค‘์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์ด ์žˆ๋Š”๋ฐ, ์ด๋Š” OOP ๋‹ค์ค‘์ƒ์†์— ์žˆ์–ด ์ฃฝ์Œ์˜ ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ ๋•Œ๋ฌธ์ด๋‹ค.

์ฃฝ์Œ์˜ ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๋ž€ ์œ„์˜ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ A ํด๋ž˜์Šค๋ฅผ B, C๊ฐ€ ์ƒ์†์„ ๋ฐ›๊ณ  D ํด๋ž˜์Šค์—์„œ ๋‹ค์ค‘์ƒ์†์œผ๋กœ B, C๋ฅผ ์ƒ์† ๋ฐ›์•˜๋‹ค๋ฉด, ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ๋‹ค์ด์•„๋ชฌ๋“œ ๊ตฌ์กฐ๊ฐ€ ํ˜•์„ฑ๋˜๊ฒŒ ๋œ๋‹ค.

์ด ๋•Œ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ, B, C์—์„œ ์žฌ์ •์˜(override)๋œ print() ๋ฉ”์„œ๋“œ๋ฅผ D ํด๋ž˜์Šค์—์„œ ํ˜ธ์ถœ์„ ํ•œ๋‹ค๋ฉด ์–ด๋Š ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์—์„œ ์ •์˜๋œ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ์ด ๋˜์–ด์•ผ ํ• ๊นŒ ? ์ด๋Ÿฐ ๋ชจํ˜ธ์„ฑ์œผ๋กœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๊ฒƒ์„ ์ฃฝ์Œ์˜ ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๋ผ๊ณ  ํ•œ๋‹ค.

Dart ์–ธ์–ด์—์„œ ์ด๋Ÿฌํ•œ ๋ชจํ˜ธ์„ฑ์„ ํ•ด๊ฒฐํ•˜์—ฌ ๋‹ค์ค‘์ƒ์†์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

์šฐ์„  ๋‹ค์ค‘์ƒ์† ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ธฐ์— ์•ž์„œ, extends ์ƒ์†์€ ๋‹ค์ค‘์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

Flutter 3 ๋ฒ„์ „์ด ๋‚˜์˜ค๊ธฐ ์ „์—๋Š” extends์—์„œ๋„ ๋‹ค์ค‘์ƒ์†์„ with ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ Flutter 3 ๋ถ€ํ„ฐ๋Š” ๋‹ค์ค‘์ƒ์†์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด implements๋Š” ๋‹ค์ค‘ ์ƒ์†์ด ๊ฐ€๋Šฅํ• ๊นŒ ? implements ์ƒ์†์€ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์š”์†Œ๋ฅผ ์žฌ์ •์˜(override)ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๋Ÿฌ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

Hero์˜ ๊ณต๊ฒฉ๋ ฅ๊ณผ ๋ฐฉ์–ด๋ ฅ์„ ๊ฐ€์ง€๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค์™€, ๋งˆ๋ธ” ํžˆ์–ด๋กœ์˜ ์š”์†Œ์ธ tier๋ฅผ ๊ฐ€์ง€๋Š” MarvelHero ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์ž.

abstract class Hero {
  int getAttack();
  int getDefence();
}

abstract class MarvelHero {
  final int tier;

  const MarvelHero(this.tier);
}

Hero, MarvelHero ํด๋ž˜์Šค๋ฅผ ๋‹ค์ค‘์ƒ์†์œผ๋กœ ์ƒ์† ๋ฐ›๋Š” IronMan ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ ๋’ค, ์žฌ์ •์˜(override) ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

class IronMan implements Hero, MarvelHero {
  
  int getAttack() => (10 - tier) * 100;

  
  int getDefence() => (10 - tier) * 20;

  
  int get tier => 9;
}

๋งŒ์•ฝ์— MarvelHero ํด๋ž˜์Šค์— Hero์— ์žˆ๋Š” ๋™์ผํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

๊ฒฐ๊ณผ๋Š” ๋™์ผํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€ ๋˜๋”๋ผ๋„, ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์žฌ์ •์˜(override) ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•ด๋„ ์ƒ๊ด€์—†๋‹ค.

class MarvelHero {
  final int tier;
  int getAttack() => 100;
  int getDefence() => 100;
  const MarvelHero(this.tier);
}

ํด๋ž˜์Šค ํ•˜๋‚˜๋ฅผ ๋” ์ƒ์„ฑํ•ด์„œ ์ด ์„ธ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋„๋ก ํ•ด์ฃผ์ž.

class Actor {
  final String name;

  const Actor(this.name);
}

Actor ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋”๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค. ์žฌ์ •์˜(override)๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

implements ์ƒ์†์—์„œ๋Š” ๋‹จ์ผ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋˜ ๋‹ค์ค‘์ƒ์†์„ ๋ฐ›๋˜ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

class IronMan implements Hero, MarvelHero, Actor {
  
  int getAttack() => (10 - tier) * 100;

  
  int getDefence() => (10 - tier) * 20;

  
  int get tier => 9;

  
  String get name => "Robert John Downey Jr";
}

์œ„์—์„œ extends ์ƒ์†์€ ๋‹ค์ค‘์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ , ๋‹ค์ค‘์ƒ์†์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๊ทธ ๋ฐฉ๋ฒ•์ด ๋ฐ”๋กœ mixin ์ƒ์† ์ด๋‹ค.

mixin

Mixins | Dart

์ด์–ด์„œ ํ•œ ๊ฐœ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ extends ์ƒ์†์„ ์‚ฌ์šฉํ•ด ์ƒ์† ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์ธ mixin์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

์ƒ์†์— ๋Œ€ํ•œ ๋ถ€๋ถ„์„ ์„ค๋ช…ํ•  ๋•Œ์— extends, implements, mixin ์ด๋ ‡๊ฒŒ ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๊ณ  ํ–ˆ์—ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€๋Š” mixin์— ๋Œ€ํ•œ ์„ค๋ช…์€ ํ•˜์ง€๋„ ์•Š๊ณ , extends, implements์— ๋Œ€ํ•ด์„œ๋งŒ ์„ค๋ช… ํ–ˆ์—ˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๊ฐ€ ๋ฐ”๋กœ mixin์€ ๋‹จ์ผ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ ์ƒ์† ๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋ฅผ extends ์ƒ์†์„ ์‚ฌ์šฉํ•ด ๋‹ค์ค‘์ƒ์† ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์•ž์„œ ์„ค๋ช… ํ–ˆ๋“ฏ์ด Flutter 3์—์„œ ์—…๊ทธ๋ ˆ์ด๋“œ๋œ ๋ถ€๋ถ„์ด ๋ฐ”๋กœ mixin์ด๋‹ค. ์ด์ „์—๋Š” with ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์ค‘์ƒ์† ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, 3 ๋ฒ„์ „์œผ๋กœ ๋„˜์–ด์˜ค๋ฉด์„œ, mixin์„ ์‚ฌ์šฉํ•ด์„œ๋งŒ ๋‹ค์ค‘์ƒ์†์ด ๊ฐ€๋Šฅํ•ด ์กŒ๋‹ค.

์ด์ „ ๋ฒ„์ „์˜ ๋‹ค์ค‘์ƒ์† ๊ธฐ๋Šฅ์ธ with์— ๋Œ€ํ•ด์„œ ๊ถ๊ธˆํ•˜์‹œ๋‹ค๋ฉด ์•„๋ž˜ ๊ธ€์„ ์ฐธ๊ณ ํ•˜์‹œ๊ธธ ๋ฐ”๋ž€๋‹ค.

- [Dart] Class ์ด ์ •๋ฆฌ (์ƒ์† / ์žฌ์ •์˜ / ์ถ”์ƒํ™”)

์—ฌ๊ธฐ์„œ๋Š” mixin์„ ์‚ฌ์šฉํ•œ ๋‹ค์ค‘์ƒ์†๋งŒ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ๋‹ค.

Dart์—์„œ mixin์— ๋Œ€ํ•œ ์„ค๋ช…์„ ๋ญ๋ผ๊ณ  ํ•˜๊ณ  ์žˆ์„๊นŒ ?

"๋‹ค์ˆ˜์˜ ํด๋ž˜์Šค ๊ณ„์ธต์—์„œ ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค."

์ด์ „์—๋Š” with๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์ค‘์ƒ์†์„ ํ•  ์ˆ˜ ์žˆ์—ˆ์—ˆ๋‹ค.

class A {}

class B {}

class C extends A with B {}

์ด์ œ ๋‹ค์ค‘์ƒ์†์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” mixin์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

class A {}

mixin B {}

class C extends A with B {}

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ mixin์— ๋Œ€ํ•ด์„œ ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜์ž. ์ฐธ๊ณ ๋กœ ๊ธฐ๋Šฅ์ด ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ๋‹ค.

๋จผ์ € mixin ํด๋ž˜์Šค๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” with ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์ค‘์ƒ์† ํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ with๋Š” mixin์„ ์œ„ํ•œ ํ‚ค์›Œ๋“œ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. mixin์œผ๋กœ ์ƒ์„ฑ๋œ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ with ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ์–ด์•ผ๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

A ํด๋ž˜์Šค๋Š” ์ผ๋ฐ˜ ํด๋ž˜์Šค์ด๊ณ , B๋Š” mixin์œผ๋กœ ์ƒ์„ฑํ•˜์˜€๋‹ค.

C ํด๋ž˜์Šค์—์„œ ๋‹ค์ค‘์ƒ์†์„ ์œ„ํ•ด ์ผ๋ฐ˜ ํด๋ž˜์Šค์ธ A ํด๋ž˜์Šค๋ฅผ extends ์ƒ์†์„ ๋ฐ›๊ณ , with ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด mixin์œผ๋กœ ์ƒ์„ฑํ•œ B๋ฅผ ์ƒ์† ๋ฐ›๊ฒŒ ๋˜๋ฉด C ํด๋ž˜์Šค๋Š” A์˜ ์š”์†Œ์™€ B์˜ ์š”์†Œ๋ฅผ ๋ชจ๋‘ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

class A {
  void logA() => print("A Class");
}

mixin B {
  void logB() => print("B Mixin");
}

class C extends A with B {}

C ํด๋ž˜์Šค๋Š” A์™€ B์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

void main() {
  C c = C();
  c.logA();
  // A Class

  c.logB();
  // B Mixin
}

์ฐธ๊ณ ๋กœ mixin ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ๋œ ํด๋ž˜์Šค๋ฅผ implements ์ƒ์†์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, with ํ‚ค์›Œ๋“œ ์—†์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

ํ•˜์ง€๋งŒ implements ์ƒ์†์œผ๋กœ mixin ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋”๋ผ๋„, ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๋‹น์—ฐํžˆ ์žฌ์ •์˜(override)ํ•ด์•ผ ํ•œ๋‹ค.

mixin A {
  void logA();
}

mixin B {
  void logB();
}

mixin ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ๋œ A, B ํด๋ž˜์Šค๋ฅผ ๋‹จ์ผ ํด๋ž˜์Šค๋งŒ ์ƒ์† ๋ฐ›์•„๋„ ๋˜๊ณ , ๋‹ค์ค‘์ƒ์† ๋ฐ›์•„๋„ ๋œ๋‹ค.

class C implements A, B {
  
  void logA() => print("A mixin");

  
  void logB() => print("B mixin");
}

๋‹ค์‹œ extends๋ฅผ ์‚ฌ์šฉํ•œ ๋‹ค์ค‘์ƒ์†์„ ์œ„ํ•œ mixin ์ƒ์†์œผ๋กœ ๋Œ์•„์˜ค์ž.

์ฟ๋ฐ˜ ํด๋ž˜์Šค๊ฐ€ ์—†์ด mixin ํด๋ž˜์Šค๋งŒ ๋‹ค์ค‘์ƒ์†ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ ?

with ํ‚ค์›Œ๋“œ๋กœ extends ์—†์ด๋„ ๋‹ค์ค‘์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

mixin A {
  void logA() => print("A mixin");
}
mixin B {
  void logB() => print("B mixin");
}

class C with A, B {}

์—ฌ๊ธฐ์„œ ํ•œ ๊ฐ€์ง€ ์˜๋ฌธ์ ์ด ๋ฐœ์ƒํ•œ๋‹ค. ๋งŒ์ผ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋™์ผํ•˜๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

A,B ํด๋ž˜์Šค๋Š” ๊ฐ๊ฐ log() ๋ผ๋Š” ๋™์ผํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๋‘ ๊ฐœ์˜ ํด๋ž˜์Šค ์ค‘ ์–ด๋Š ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰์ด ๋ ๊นŒ ? ์•„๋‹ˆ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ ?

mixin A {
  void log() => print("A mixin");
}
mixin B {
  void log() => print("B mixin");
}

class C with A, B {}

์ •๋‹ต์€ B์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰์ด ๋˜์—ˆ๋‹ค.

void main() {
  C c = C();
  c.log();
  // B mixin
}

mixin ์šฐ์„ ์ˆœ์œ„

mixin ๋‹ค์ค‘์ƒ์†์€ ๋™์ผ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์šฐ์„  ์ˆœ์œ„๊ฐ€ ์ •ํ•ด์ ธ ์žˆ๋‹ค.

๋ฐ”๋กœ with ํ‚ค์›Œ๋“œ์˜ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ mixin ํด๋ž˜์Šค ๋ถ€ํ„ฐ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž. D mixin ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€๋กœ ์ƒ์„ฑํ•ด๋ณด์ž.

mixin D {
  void log() => print("D mixin");
}

D mixin ํด๋ž˜์Šค๊ฐ€ ๊ฐ€์žฅ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋„๋ก ๋‹ค์ค‘์ƒ์†์„ ํ•˜๋„๋ก ํ•˜์ž.

class C with A, B, D {}

์˜ˆ์ƒ๋Œ€๋กœ D์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰์ด ๋˜์—ˆ๋‹ค.

void main() {
  C c = C();
  c.log();
  // D mixin
}

๋™์ผํ•œ ๊ตฌ์กฐ์—์„œ A ํด๋ž˜์Šค๋งŒ ์ผ๋ฐ˜ ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝํ•ด ์ฃผ์ž.

class A {
  void log() => print("A mixin");
}

class C extends A with B, D {}

๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๊ฒŒ with ํ‚ค์›Œ๋“œ์˜ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ mixin ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰์ด ๋œ๋‹ค.

void main() {
  C c = C();
  c.log();
  // D mixin
}

mixin ๋‹ค์ค‘์ƒ์†์—์„œ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์ˆœ์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์ •ํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์—, with ํ‚ค์›Œ๋“œ์— ๋”ฐ๋ฅธ ์ˆœ์„œ๋ฅผ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๋ฉ”์„œ๋“œ ์™ธ์—๋„ ๋ฉค๋ฒ„๋ณ€์ˆ˜์˜ ์šฐ์„ ์ˆœ์œ„๋„ ๋™์ผํ•˜๋‹ค.

mixin A {
  final String name = "A";
}

mixin B {
  final String name = "B";
}

class C with A, B {}

void main() {
  C c = C();
  print(c.name);
  // B
}

on

on ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด์„œ๋„ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

mixin ์—์„œ๋Š” on ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ด๋‹ค.

Sometimes you might want to restrict the types that can use a mixin.
For example, the mixin might depend on being able to invoke a method
that the mixin doesnโ€™t define.
As the following example shows, you can restrict a mixinโ€™s use
by using the on
keyword to specify the required superclass:

on ํ‚ค์›Œ๋“œ๋Š” mixin์˜ ์‚ฌ์šฉ์„ ํŠน์ • ํด๋ž˜์Šค ๋‚ด์—์„œ ์ œํ•œํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.

mixin์œผ๋กœ ์ƒ์„ฑ๋œ ํด๋ž˜์Šค์˜ ์ƒ์†์„ ํŠน์ • ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•˜์„ ๋•Œ์—๋งŒ, ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ๋‹ค.

์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ํŠน์ • ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก mixin ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž.

๋””๋ฐ”์ด์Šค์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด์ž.
ํ•˜์ง€๋งŒ ๋””๋ฐ”์ด์Šค๋งˆ๋‹ค ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ์ด ์žˆ๊ณ , ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.

Phone๊ณผ PC ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ name์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์—ˆ๋‹ค.

abstract class Phone {
  String get name;
}

abstract class PC {
  String get name;
}

์ด์ œ ๊ธฐ๋Šฅ๋“ค์„ ์ƒ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค. Photo ํด๋ž˜์Šค๋Š” ์‚ฌ์ง„์ฒฉ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , Lock ํด๋ž˜์Šค๋Š” ๋””๋ฐ”์ด์Šค ์ž ๊ธˆ์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

mixin Photo {
  void openPhotos() => print("์‚ฌ์ง„์ฒฉ ์˜คํ”ˆ !");
}
mixin Lock {
  void unLock() => print("์ž ๊ธˆ ํ•ด์ œ !");
}

๊ทธ๋Ÿฐ๋ฐ, ์—ฌ๊ธฐ์— ์ถ”๊ฐ€๋กœ ์นด๋ฉ”๋ผ๋กœ ์‚ฌ์ง„์„ ์ฐ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” Camera ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜์ž. ๋‹ค๋งŒ, ์นด๋ฉ”๋ผ ๊ธฐ๋Šฅ์€ PC ํด๋ž˜์Šค์—์„œ๋Š” ์ƒ์†๋ฐ›์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๊ณ , Phone ํด๋ž˜์Šค์—์„œ๋งŒ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž.

์ด๋Ÿด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๋ฐ”๋กœ on ํ‚ค์›Œ๋“œ์ด๋‹ค.

์ด์ œ Camera ํด๋ž˜์Šค๋Š” Phone ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ๋งŒ ์‚ฌ์šฉ ํ•˜๋„๋ก ์ œํ•œ์ด ๋˜์—ˆ๋‹ค.

mixin Camera on Phone {
  void takePicture() => print("์‚ฌ์ง„ ์ดฌ์˜ !");
}

๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋Š” ๋ชจ๋‘ ์ƒ์„ฑ ํ–ˆ์œผ๋‹ˆ, ์ด์ œ IPhone ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค์ค‘์ƒ์†์œผ๋กœ Phone, Photo, Lock, Camera ํด๋ž˜์Šค๋ฅผ ๋ฐ›๋„๋ก ํ•˜์ž.

class IPhone extends Phone with Photo, Lock, Camera {
  
  String get name => "iPhone 15";
}

์ด๋ฒˆ์—๋Š” Macbook ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  PC, Photo, Lock ํด๋ž˜์Šค๋ฅผ ๋‹ค์ค‘์ƒ์† ๋ฐ›๋„๋ก ํ•˜์ž.

class Macbook extends PC with Photo, Lock {
  
  String get name => "Macbook";
}

Macbook ํด๋ž˜์Šค์— ์ถ”๊ฐ€๋กœ Camera ํด๋ž˜์Šค๋ฅผ ์ƒ์†์— ์ถ”๊ฐ€ํ•ด๋ณด์ž.

class Macbook extends PC with Photo, Lock, Camera {
  
  String get name => "Macbook";
}

์ด๋ ‡๊ฒŒ ๋˜๋ฉด Camera ํด๋ž˜์Šค์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

'Camera' can't be mixed onto 'PC' because 'PC' doesn't implement 'Phone'.
Try extending the class 'Camera'.

Phone ํด๋ž˜์Šค์—์„œ๋งŒ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‚ด์šฉ์ด๋‹ค.

Camera ํด๋ž˜์Šค๋Š” Phone์„ ์ƒ์† ๋ฐ›์•„์•ผ์ง€๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œํ•œ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ˜๋“œ์‹œ Phone ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๊ฒŒ ๋˜์–ด์žˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, Phone ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜(member variable), ๋ฉ”์„œ๋“œ(method)์˜ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค.

mixin Camera on Phone {
  void takePicture() => print("$name ์‚ฌ์ง„ ์ดฌ์˜ !");
}

์ผ๋ฐ˜ ํด๋ž˜์Šค๋งŒ ์ƒ์†์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , mixin ํด๋ž˜์Šค๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

mixin A {}
mixin B on A{}

on ํ‚ค์›Œ๋“œ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ mixin ์„ ์ถ”๊ฐ€ํ•˜์—ฌ๋„ ๋œ๋‹ค. ๋‹จ ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์ถ”๊ฐ€๋œ ๋ชจ๋“  mixin์„ ๋จผ์ € ์ƒ์† ๋ฐ›์•„์•ผ๋งŒ ํ•œ๋‹ค.

mixin A {}
mixin B {}
mixin C on A, B {}

์•„๋ž˜ ์ฝ”๋“œ๋Š” A, B ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก C ํด๋ž˜์Šค๋ฅผ ์ œํ•œ ํ•˜์˜€๋Š”๋ฐ, B ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

class Test with A, C {}

์•„๋ž˜ ์ผ€์ด์Šค๋Š” B๋ฅผ ์ถ”๊ฐ€ ํ•˜์˜€๋Š”๋ฐ๋„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋‹ค.
์œ„์˜ ์ผ€์ด์Šค์—์„œ๋Š” B๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ ํ•˜์˜€๋Š”๋ฐ, ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์™œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ ?

class Test with A, C, B {}

์ด์œ ๋Š” ์ˆœ์„œ์— ์žˆ๋‹ค. C ํด๋ž˜์Šค๋ฅผ A, B ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋œ ๊ฒฝ์šฐ์—๋งŒ ์ƒ์† ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œํ•œ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์—, ์ƒ์† ์ด๋ฃจ์–ด์ง€๋Š” ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ๋„ on ํ‚ค์›Œ๋“œ๋กœ ์ œํ•œํ•œ ํด๋ž˜์Šค๋ฅผ ๋จผ์ € ์ƒ์† ๋ฐ›์•„์™€์•ผ๋งŒ ํ•˜๊ฒŒ ๋œ๋‹ค.

A, B ํด๋ž˜์Šค๊ฐ€ ๋จผ์ € ์ƒ์†์„ ์ถ”๊ฐ€ํ•ด์•ผ C ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

class Test with A, B, C {}

์ด๋ฒˆ์—๋Š” ์ข€ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋‹ค์ค‘์ƒ์†์„ ์ œํ•œํ•˜๋„๋ก ํ•ด๋ณด์ž.

A๋ฅผ ์ƒ์„ฑํ•˜๊ณ , B๋Š” Aํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋œ ๊ฒฝ์šฐ์—๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๊ณ , C๋Š” B์˜ ์ƒ์†์ด ์ด๋ฃจ์–ด์ ธ์•ผ๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

ํ•ด๋‹น ์ผ€์ด์Šค์—์„œ A๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ์ „๋ถ€ ํŠน์ • ํด๋ž˜์Šค์—์„œ๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

mixin A {}
mixin B on A {}
mixin C on B {}

A ํด๋ž˜์Šค๋Š” ์ œํ•œ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‹น์—ฐํžˆ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

class Test with A {}

C ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„๋ณด์ž. C๋Š” B ํด๋ž˜์Šค๊ฐ€ ์ƒ์† ๋˜์–ด์•ผ๋งŒ ๊ฐ€๋Šฅํ•˜๊ธฐ์— B๋ฅผ ๋จผ์ € ์ƒ์†ํ•ด ์ฃผ๋„๋ก ํ•˜์˜€๋‹ค.

ํ•˜์ง€๋งŒ ์—ญ์‹œ๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. B๋Š” A ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋œ ์ƒํƒœ์—์„œ๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

class Test with B, C {}

๊ฒฐ๊ตญ on ํ‚ค์›Œ๋“œ๋กœ ์ œํ•œ๋œ ํด๋ž˜์Šค์—์„œ์˜ ์ƒ์†์„ ๊ตฌํ˜„ํ•  ๋•Œ์—๋Š” ๊ตฌ์กฐ์˜ ์„ค๊ณ„์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ํ•ด๋ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

class Test with A, B, C {}

๋ณต์žกํ•˜๋”๋ผ๋„ on ํ‚ค์›Œ๋“œ๋กœ ํŠน์ • ํด๋ž˜์Šค์—์„œ๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œํ•œํ•˜๊ฒŒ ๋˜๋ฉด, ์ž˜๋ชป๋œ ์ƒ์†์„ ์‚ฌ์ „์— ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

mixin์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

ํฌ๋ฅด์‰ ์ž๋™์ฐจ์˜ ํŠน์ง• ๋ฐ ์†์„ฑ์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

๋จผ์ €, ์ž๋™์ฐจ์˜ ์ข…๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ElectircCar(์ „๊ธฐ์ฐจ), EngineCar(๋‚ด์—ฐ๊ธฐ๊ด€์ฐจ), HybridCar(ํ•˜์ด๋ธŒ๋ฆฌ๋“œ์ฐจ) ํด๋ž˜์Šค๋ฅผ ๊ฐ๊ฐ ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋กœ ์ƒ์„ฑํ•ด ์ฃผ์ž.

abstract class ElectricCar {}

abstract class EngineCar {}

abstract class HybridCar {}

์ž๋™์ฐจ์˜ ์ข…๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜์˜€๊ณ , ๋‹ค์Œ์œผ๋กœ๋Š” ๋ถ€ํ’ˆ์ด๋‚˜ ์†์„ฑ๋“ค์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜์ž.

์ž๋™์ฐจ์— ์‚ฌ์šฉ๋  ๋™๋ ฅ์›์ธ Electric(์ „๊ธฐ), Engine(์—”์ง„)์„ mixin ํด๋ž˜์Šค๋กœ ์ƒ์„ฑํ•ด ์ฃผ์—ˆ๋‹ค.

mixin Electric {}

mixin Engine {}

์—ฐ๋ฃŒ ๋ถ€๋ถ„์„ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ธ๋ฐ, Fuel(์—ฐ๋ฃŒ) ํด๋ž˜์Šค๋Š” ๋ฐ˜๋“œ์‹œ Engine(์—”์ง„) ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

์—ฐ๋ฃŒ์˜ ์ข…๋ฅ˜์ธ Gasoline(ํœ˜๋ฐœ์œ ), Diesel(๊ฒฝ์œ ) ํด๋ž˜์Šค๋Š” Fuel(์—ฐ๋ฃŒ), Engine(์—”์ง„) ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์•ผ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œํ•œ ํ•˜์˜€๋‹ค.

mixin Fuel on Engine {}

mixin Gasoline on Engine, Fuel {}

mixin Diesel on Engine, Fuel {}

์ด๋ฒˆ์—๋Š” Battery ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๋™๋ ฅ์›์ธ Electric(์ „๊ธฐ) ํด๋ž˜์Šค์—์„œ๋งŒ ์ƒ์† ๋ฐ›๋„๋ก ์ œํ•œํ•˜๊ณ , ๋ฐฐํ„ฐ๋ฆฌ๋ฅผ ์ถฉ์ „ํ•  Charger(์ถฉ์ „๊ธฐ) ๋ถ€ํ’ˆ์€ Electric, Battery ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ์„ ์ œํ•œํ•˜์˜€๋‹ค.

mixin Battery on Electric {}

mixin Charger on Electric, Battery {}

๋งˆ์ง€๋ง‰ ๋ถ€ํ’ˆ์œผ๋กœ DPF(์—ฐ๋ฃŒ์ €๊ฐ์žฅ์น˜) ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ํ•ด๋‹น ๋ถ€ํ’ˆ์€ Engine(์—”์ง„), Fuel(์—ฐ๋ฃŒ), Diesel(๊ฒฝ์œ ) ์†์„ฑ์„ ์ƒ์† ๋ฐ›์•„์•ผ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ๋งŒ์ผ Gasoline(ํœ˜๋ฐœ์œ )๋ฅผ ์—ฐ๋ฃŒ๋กœ ์‚ฌ์šฉํ•˜๋ฉด, ์ƒ์† ๋ฐ›์„ ์ˆ˜ ์—†๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

mixin DPF on Engine, Fuel, Diesel {}

์ž ์ด์ œ ์ž๋™์ฐจ์˜ ์ข…๋ฅ˜ ๋ถ€ํ„ฐ ๋ถ€ํ’ˆ๊นŒ์ง€ ์ถ”์ƒํ™”๋ฅผ ํ•˜์˜€์œผ๋‹ˆ, ๊ฐ ๋ชจ๋ธ๋งˆ๋‹ค ํŠน์ง• ๋ฐ ์†์„ฑ์„ ๋‹ค์ค‘์ƒ์† ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž

class Boxter extends EngineCar with Engine, Fuel, Gasoline {}

class Taycan extends ElectricCar with Electric, Battery, Charger {}

class Cayenne extends EngineCar with Engine, Fuel, Diesel, DPF {}

class PanameraHybrid extends HybridCar with Engine, Electric, Fuel, Gasoline, Battery, Charger {}

์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ mixin์„ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์˜ ํŠน์ง•์ด๋‚˜ ์†์„ฑ๋“ค์„ ๋‹ค์ค‘์ƒ์† ๋ฐ›์•„ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’ํžˆ๋ฉด์„œ, ํ™•์žฅ์„ฑ ์žˆ๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๋“œ๋””์–ด ์ƒ์†์— ๋Œ€ํ•œ ๋ถ€๋ถ„์ด ๋์ด ๋‚ฌ๋‹ค.

๋‹จ์ผ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋Š” ๋ฐฉ๋ฒ• ๋ถ€ํ„ฐ ๋‹ค์ค‘์ƒ์† ๊นŒ์ง€๋ฅผ ์‚ดํŽด ๋ดค์œผ๋ฉฐ, extends, implements, mixin์„ ์‚ฌ์šฉํ•œ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์˜ ์†์„ฑ์„ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ์ƒ์† ๋ฐ›๋Š” ๋ฐฉ๋ฒ• ๋ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ๋ฐ ํŠน์ง•์— ๋Œ€ํ•ด์„œ๋„ ์•Œ์•„๋ดค๋‹ค.

์ƒ์† ๋ถ€๋ถ„์€ ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ๋ฉด, ์–ด๋ ค์šด ๋‚ด์šฉ์ด๋‹ˆ ์ต์ˆ™ํ•ด์งˆ ๋•Œ๊นŒ์ง€ ์—ฐ์Šต์„ ๋งŽ์ด ํ•ด๋ณด์‹œ๊ธธ ๋ฐ”๋ž€๋‹ค.

factory

Factory Pattern(ํŒฉํ† ๋ฆฌ ํŒจํ„ด) ?

Flutter๋กœ ํด๋ž˜์Šค(class)๋ฅผ ๋‹ค๋ฃจ๋‹ค ๋ณด๋ฉด ์ž์ฃผ ์ ‘ํ•˜๋Š” ํ‚ค์›Œ๋“œ ์ค‘์— ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ factory ํ‚ค์›Œ๋“œ์ด๋‹ค.

factory ํ‚ค์›Œ๋“œ์˜ ๋Œ€ํ‘œ์ ์ธ ์‚ฌ์šฉ์€ JSON ์ง๋ ฌํ™”๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์— ์‚ฌ์šฉ๋˜๊ธฐ์— ๋‚ฏ์„  ํ‚ค์›Œ๋“œ๋Š” ์•„๋‹ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด factory๋Š” ๋ญ˜๊นŒ ?

์šฉ์–ด์  ํ•ด์„์œผ๋กœ ๋ณด๋ฉด, ๊ณต์žฅ์„ ๋– ์˜ฌ๋ฆด ์ˆ˜๊ฐ€ ์žˆ์–ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์‚ฐํ•ด๋‚ด๋Š” ๊ณต์žฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ณต์žฅ๋ณด๋‹ค๋Š” ์ฐฝ๊ณ (warehouse)์˜ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ๋ณด๋Š” ๊ฒƒ์ด ๋” ์ ํ•ฉํ•˜๋‹ค.

๋˜ํ•œ factory๋Š” ํ‚ค์›Œ๋“œ์ด๊ธฐ๋„ ํ•˜๊ณ , ํŒจํ„ด(Pattern) ์ด๊ธฐ๋„ ํ•œ๋‹ค.

๋จผ์ € ํ‚ค์›Œ๋“œ๋กœ factory์˜ ์—ญํ• ์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

factory Keyword

factory ํ‚ค์›Œ๋“œ๋Š” ์ƒ์„ฑ์ž(constructor)์™€ ์œ ์‚ฌํ•ด ๋ณด์ด์ง€๋งŒ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์—ญํ• ๊ณผ ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ, ์ƒ์„ฑ์ž(constructor)๊ฐ€ ํ˜ธ์ถœ์‹œ๋งˆ๋‹ค ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์‚ฐํ•˜๋Š” ๊ฒƒ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ factory๋Š” ์ด๋ฏธ ์ƒ์‚ฐ๋œ ์ธ์Šคํ„ด์Šค(instance)๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์žฌ์ƒ์‚ฐ ํ•œ๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค. ๋˜ํ•œ ์„œ๋ธŒํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์—ญํ• ์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์œ„์˜ ์„ค๋ช… ์ค‘ ์ธ์Šคํ„ด์Šค(instance)๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์žฌ์ƒ์‚ฐ ํ•œ๋‹ค๋Š” ํŠน์ง•์„ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern) ์œผ๋กœ ์ดํ•ดํ•˜๊ณ  ์„ค๋ช…ํ•˜๋Š” ๊ธ€๋“ค์ด ๋งŽ์€๋ฐ, factory๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern) ๋‚ด์—์„œ ์‚ฌ์šฉ๋  ๋•Œ์—๋งŒ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์‚ฐํ•˜์ง€ ์•Š๋„๋ก ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ณ , ์ผ๋ฐ˜ ํด๋ž˜์Šค ๋‚ด์—์„œ๋Š” ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์‚ฐํ•˜๊ณ  ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์„ ๊ฐ€์ง„๋‹ค๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern) ์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃจ๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์„ค๋ช…์œผ๋กœ๋Š” ์ดํ•ด๊ฐ€ ์•ˆ๋˜๊ฒ ์ง€๋งŒ, ์ „ํ˜€ ๋ณต์žกํ•œ ๋‚ด์šฉ์ด ์•„๋‹ˆ๋‹ค.

Device ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์ž.

class Device {
  final int id;
  final String name;

  const Device(this.id, this.name);
}

factory๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์ž.

factory๋Š” ๋ฐ˜๋“œ์‹œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ณ , ๋‹ค๋ฅธ ์œ ํ˜•์˜ ํƒ€์ž…์€ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†๋‹ค.

class Device {
  final int id;
  final String name;

  const Device({required this.id, required this.name});

  factory Device.test() => Device(id: 1, name: "name");
}

Device ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์„ฑ์ž(constructor)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , factory๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

void main() {
  Device test = Device.test();
  print(test.name);
  // name
}

factory์˜ ์œ ์šฉํ•œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๊ฐ€ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค(instance) ์œ ํ˜•์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Device ํด๋ž˜์Šค๋ฅผ iPhone, Mac, watch ์ด๋ ‡๊ฒŒ 3๊ฐœ์˜ ๊ฐ์ฒด๋กœ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

์ด๋ ‡๊ฒŒ ๊ฐ๊ฐ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋ฌธ์ œ๋Š” ํด๋ž˜์Šค(class)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๊ฐ€ ๋” ๋งŽ๋‹ค๋ฉด ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ• ์ˆ˜๋„ ์žˆ๋‹ค.

void main() {
  Device iPhone = Device(id: 0, name: "iPhone");
  Device mac = Device(id: 1, name: "Mac");
  Device watch = Device(id: 2, name: "Watch");
}

์ด๋Ÿด ๋•Œ์— factory ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ํด๋ž˜์Šค(class)๋‚ด์— ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ์ข‹๋‹ค.

class Device {
  final int id;
  final String name;

  const Device({required this.id, required this.name});

  factory Device.iPhone() => Device(id: 0, name: "iPhone");
  factory Device.mac() => Device(id: 1, name: "Mac");
  factory Device.watch() => Device(id: 2, name: "Watch");
}

๊ฐ„๋‹จํ•˜๊ฒŒ ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

void main() {
  Device iPhone = Device.iPhone();
  Device mac = Device.mac();
  Device watch = Device.watch();
}

factory ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ฐ€ ์ฃผ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ฐ”๋กœ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

ํด๋ž˜์Šค๋ฅผ Nullable๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ณ , ๊ธฐ๋ณธ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, factory๋ฅผ ํ™œ์šฉํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

class Device {
  final int id;
  final String name;

  const Device({required this.id, required this.name});

  factory Device.empty() => Device(id: 0, name: "");
}

์ด๋ฒˆ์—๋Š” factory์˜ ์ฃผ์š” ํŠน์ง• ์ค‘ ํ•˜๋‚˜์ธ ์„œ๋ธŒํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ๋‹ค.

Device ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์ž.

class Device {
  final int id;

  const Device(this.id);
}

Phone ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)๋กœ Device ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋„๋ก ํ•˜์ž.

class Phone implements Device {
  final String model;

  const Phone(this.model);

  
  int get id => 0;
}

์ด์ œ ๋‹ค์‹œ Device ํด๋ž˜์Šค๋กœ ์™€์„œ, ์„œ๋ธŒํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์ž.

Device ํด๋ž˜์Šค์—์„œ ์„œ๋ธŒํด๋ž˜์Šค์ธ Phone ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™œํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

class Device {
  final int id;

  const Device(this.id);

  factory Device.phone() => Phone("iPhone");
}

factory Pattern

ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์€ ์•ž์„œ ๋ฐฐ์› ๋˜ factory ํ‚ค์›Œ๋“œ์˜ ํŠน์ง•์„ ํ™œ์šฉํ•œ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋กœ์จ, ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์—์„œ ์•Œ๋ ค์ง€์ง€ ์•Š์€ ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)์—์„œ ๊ฒฐ์ •ํ•˜๊ฒŒ ํ•˜๋Š” ํŒจํ„ด์ด๋‹ค.

Flutter์—์„œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์€ ์ฃผ๋กœ UI ์ž‘์—…์— ์ฃผ๋กœ ์‚ฌ์šฉ์ด ๋˜๊ณ  ์žˆ๋‹ค.

Flutter๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค ๋ณด๋‹ˆ, UI ์š”์†Œ๋ฅผ ๋งŒ๋“ค ๋•Œ์—๋„ ๊ฐ ํ”Œ๋žซํผ ๋งˆ๋‹ค ์ž‘๋™๋˜๊ฑฐ๋‚˜ ๊ตฌํ˜„๋˜๋Š” ๋ถ€๋ถ„์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ํ™œ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๋ฌผ๋ก  ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์ด ํ•„์ˆ˜์ ์ธ ์š”์†Œ๋Š” ์•„๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์–ผ๋งˆ๋“ ์ง€ ๊ตฌํ˜„ ํ•˜๋Š”๋ฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ๋™์ž‘์„ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์„ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ์‚ฌ์šฉํ•ด ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜์ž.

ํ•ด๋‹น ๊ธ€์€ Dart ์–ธ์–ด๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๊ณ , Flutter๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ์— ํ…์ŠคํŠธ๋กœ๋งŒ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

PlatformComponent ์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

abstract class PlatformComponent {
  void onTap();

}

ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›๋Š” ๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ์„ ์ƒ์„ฑํ•ด์ฃผ๋„๋ก ํ•˜์ž.

class AndroidButton implements PlatformComponent {
  
  void onTap() => print("์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„ํŠผ");
}

class IOSButton implements PlatformComponent {
  
  void onTap() => print("iOS ๋ฒ„ํŠผ");
}

class WebButton implements PlatformComponent {
  
  void onTap() => print("์›น ๋ฒ„ํŠผ");
}

์ด์ œ PlatformComponent ์ถ”์ƒ(abstract)ํด๋ž˜์Šค์— ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž.

UI ์ปดํฌ๋„ŒํŠธ ์ค‘ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ธ๋ฐ, ํ”Œ๋žซํผ์€ ๊ณ ์œ  id๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•˜๊ฒ ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Flutter์—์„œ๋Š” enum(์—ด๊ฑฐํ˜•) ์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Dart ์–ธ์–ด์—๋Š” enum(์—ด๊ฑฐํ˜•) ๊ฐœ๋…์ด ์—†์–ด ์ •์ˆ˜ํ˜•์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๊ฐ๊ฐ ํ”Œ๋žซํผ ๋ณ„๋กœ ์ƒ์„ฑํ•œ ๋ฒ„ํŠผ์„ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ํ†ตํ•ด ์ž์‹ ํด๋ž˜์Šค(์„œ๋ธŒํด๋ž˜์Šค)๊ฐ€ ๊ธฐ๋Šฅ์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

abstract class PlatformComponent {
  void onTap();
  factory PlatformComponent.button(int type) {
    return switch (type) {
      0 => IOSButton(),
      1 => AndroidButton(),
      2 => WebButton(),
      _ => IOSButton(),
    };
  }
}

๊ฐ ํ”Œ๋žซํผ ๋ณ„๋กœ ๊ณ ์œ ์˜ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋™์ผํ•˜๊ฒŒ ๋ถ€๋ชจ ํด๋ž˜์Šค(์Šˆํผํด๋ž˜์Šค)์—์„œ ์ธ์Šคํ„ด์Šค(instance) ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

void main() {
  PlatformComponent button = PlatformComponent.button(0);
  button.onTap();
  // iOS ๋ฒ„ํŠผ
}

ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ๊ตฌํ˜„ํ•  ๋•Œ์— factory ํ‚ค์›Œ๋“œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฉฐ, ์ •์ ๋ฉ”์„œ๋“œ(StaticMethod)๋กœ๋„ ํŒจํ„ด์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.

์ƒ์† ๊ณผ์ •๊ณผ ํ—ท๊ฐˆ๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ, factory์˜ ํŠน์ง•์ธ ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ๊ณผ ์„œ๋ธŒํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ํŠน์ง•์„ ํ™œ์š”ํ•œ ๋””์ž์ธ ํŒจํ„ด์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

UI ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ๋ฅผ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์„ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•ด๋ณด๋ฉด ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•ด ๋ณผ ์ˆ˜ ์žˆ๊ณ , UI์—์„œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์˜ ์žฅ์ ์„ ๋ฐœํœ˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ๋„ ๋ณ„๋„๋กœ ๊ธ€์„ ์ž‘์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

singleton

Singleton Pattern(์‹ฑ๊ธ€ํ†ค ํŒจํ„ด) ?

ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์— ์˜ํ•ด์„œ OOP(Object Oriented Programming)์˜ ๋Œ€ํ‘œ์ ์ธ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ธ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์€ ๊ผญ!! ๋ฐ˜๋“œ์‹œ!! ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐœ๋…์„ ํ™•์‹คํžˆ ์ดํ•ด์‹œ๊ธธ ๋ฐ”๋ž€๋‹ค.

์•ž์„œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด(factory Pattern)์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณผ ๋•Œ์—, ์ž ์‹œ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์— ๋Œ€ํ•ด์„œ ์–ธ๊ธ‰ํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค.

์‹ฑ๊ธ€ํ†ค์ด๋ž€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์‹œ์— ํ˜ธ์ถœ๋˜๋Š” ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค(instance)๋งŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๊ณ , ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์€ ์ด๋Ÿฌํ•œ ์‹ฑ๊ธ€ํ†ค์˜ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•œ ๋””์ž์ธ ํŒจํ„ด์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž ๊ทธ๋ ‡๋‹ค๋ฉด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ƒ์„ฑ๋œ ํด๋ž˜์Šค์™€ ์ผ๋ฐ˜ ํด๋ž˜์Šค์˜ ์ฐจ์ด์ ์ด ๋ญ˜๊นŒ ?

์ฐจ์ด์ ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ Person ํด๋ž˜์Šค๋ฅผ ๊ฐ๊ฐ ์ผ๋ฐ˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ GeneralPerson๊ณผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ƒ์„ฑํ•œ SingletonPerson ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

class GeneralPerson {}

์ผ๋ฐ˜ ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ๋œ GeneralPerson ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ 2๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

void main() {
  GeneralPerson general1 = GeneralPerson();
  GeneralPerson general2 = GeneralPerson();
}

์ง€๊ธˆ๊นŒ์ง€ ๊ฒŒ์‹œ๊ธ€์„ ์ž˜ ๋ณด์…จ์œผ๋ฉด, general1 ๊ฐ์ฒด์™€ general2 ๊ฐ์ฒด๋Š” ๋™์ผ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์€ ์ดํ•ดํ•˜์…จ์„ ๊ฑฐ๋‹ค.

์•„์ง ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์œผ์…จ๋‹ค๋ฉด, ์™œ ๋‹ค๋ฅธ๊ฐ€ ์˜๋ฌธ์ด ์ƒ๊ธธ ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด(object)๋ฅผ ์ธ์Šคํ„ด์Šค(instance)๋ผ๊ณ  ํ•˜๊ณ , ์œ„์˜ ๊ณผ์ •์„ ์ธ์Šคํ„ด์Šคํ™”๋ผ๊ณ  ํ•˜๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ์˜ฌ๋ ค์ง€๊ฒŒ ๋œ๋‹ค๋Š” ๊ฒƒ์ธ๋ฐ, ์ธ์Šคํ„ด์Šค(instance)๋œ ๊ฐ์ฒด๋Š” ๊ณ ์œ ์˜ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ํ• ๋‹น ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด ์„œ๋กœ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— general1๊ณผ general2๋Š” ๋‹น์—ฐํžˆ ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค(instance)๊ฐ€ ๋œ๋‹ค. ํ™•์ธ์„ ํ•ด๋ณด์ž.

ํด๋ž˜์Šค๋Š” ๋™์ผ ํด๋ž˜์Šค์ด์ง€๋งŒ, ์ธ์Šคํ„ด์Šค(instance)๋Š” ๋‹ค๋ฅธ ๊ฒƒ์ด๋‹ค.

void main() {
  GeneralPerson general1 = GeneralPerson();
  GeneralPerson general2 = GeneralPerson();
  print(general1.hashCode);
  // 820663644

  print(general2.hashCode);
  // 26539618
}

๋น„๊ต ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ๋„ ์„œ๋กœ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

print(general1 == general2);
// false

๊ทธ๋ ‡๋‹ค๋ฉด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค(instance)๋Š” ์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ๋Š”์ง€๋„ ํ™•์ธํ•ด ๋ณด์ž.

์‹ฑ๊ธ€ํ†ค์„ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ๋Š” ์•„๋ž˜์—์„œ ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค. ์šฐ์„  ์ฐจ์ด์ ๋งŒ ํ™•์ธํ•ด ๋ณด์ž.

class SingletonPerson {
  static final SingletonPerson instance = SingletonPerson._internal();
  factory SingletonPerson() => instance;
  SingletonPerson._internal();
}

๋™์ผํ•˜๊ฒŒ singleton1, singleton2 2๊ฐœ์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์„ฑํ•ด๋ณด์ž.

void main() {
  SingletonPerson singleton1 = SingletonPerson();
  SingletonPerson singleton2 = SingletonPerson();
}

์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค(instance)์˜ hashCode๋ฅผ ์ถœ๋ ฅํ•ด๋ณด๋ฉด, ๋™์ผํ•œ ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ , ๋น„๊ต ์—ฐ์‚ฐ์ž์—์„œ๋„ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰ ๋™์ผ ์ธ์Šคํ„ด์Šค(instance)์ธ ๊ฒƒ์ด๋‹ค.

void main() {
  print(singleton1.hashCode);
  // 96990887
  
  print(singleton2.hashCode);
  // 96990887
  
  print(singleton1 == singleton2);
  // true
}

์•„์ง ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์œผ์…จ๋‹ค๋ฉด ๋˜ ๋‹ค๋ฅธ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž. ํด๋ž˜์Šค์— ์ •์ˆ˜ํ˜• count ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ , ๊ฐ’์„ ์ฆ๊ฐ€ ์‹œ์ผœ๋ณด๋ฉด์„œ ์ง๊ด€์ ์œผ๋กœ ์ฐจ์ด์ ์„ ํ™•์ธํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

GeneralCount ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์ž.

class GenralCount {
  int count = 0;
}

count1, count2 2๊ฐœ์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  count1์˜ count ๊ฐ’์„ 1 ์ฆ๊ฐ€ํ•ด๋ณด์ž.

count1 ๊ฐ์ฒด์˜ count ๊ฐ’์€ ๋‹น์—ฐํžˆ 1์ด ์ฆ๊ฐ€๋œ 1๋กœ ์ถœ๋ ฅ์ด๋˜๊ณ , count2 ๊ฐ์ฒด๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•ด์ฃผ์ง€ ์•Š์•˜์œผ๋‹ˆ 0์œผ๋กœ ์ถœ๋ ฅ์ด ๋œ๋‹ค.

void main() {
  GenralCount count1 = GenralCount();
  GenralCount count2 = GenralCount();
  count1.count = count1.count + 1;
  print(count1.count);
  // 1
  
  print(count2.count);
  // 0
}

๋™์ผ ๊ธฐ๋Šฅ์„ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋งŒ๋“ค์–ด๋ณด์ž.

class SingletonCount {
  static final SingletonCount instance = SingletonCount._internal();
  factory SingletonCount() => instance;
  SingletonCount._internal();

  int count = 0;
}

์ด๋ฒˆ์—๋„ count1 ๊ฐ์ฒด์˜ count ๊ฐ’๋งŒ 1 ์ฆ๊ฐ€ ์‹œ์ผฐ๋‹ค. ๊ฒฐ๊ณผ๋Š” count2 ๊ฐ์ฒด์˜ count๋„ 0์ด ์•„๋‹Œ 1๋กœ ์ถœ๋ ฅ์ด๋œ๋‹ค.

count1, count2์˜ ์ธ์Šคํ„ด์Šค(instance)๊ฐ€ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

void main() {
  SingletonCount count1 = SingletonCount();
  SingletonCount count2 = SingletonCount();
  count1.count = count1.count + 1;
  print(count1.count);
  // 1
  
  print(count2.count);
  // 1
}

์‹ฑ๊ธ€ํ†ค์— ๋Œ€ํ•ด ์ดํ•ด๊ฐ€ ๋˜์…จ์„๊ฑฐ๋ผ ์ƒ๊ฐํ•œ๋‹ค.

์ด์ œ ์‹ฑ๊ธ€ํ†ค ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

๊ธฐ๋ณธ์ด ๋˜๋Š” ์‹ฑ๊ธ€ํ†ค ๊ตฌ์กฐ์ด๋‹ค.

class Singleton {
  static final Singleton _instance = Singleton._internal();
  factory Singleton() => _instance;
  Singleton._internal();
}

๋จผ์ € ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , ์ •์ ๋ฉ”์„œ๋“œ(static)๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(instance)์— ๊ท€์†๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

Singleton._internal() ์€ ์ƒ์„ฑ์ž์ธ๋ฐ, ์ƒ์„ฑ์ž ์ด๋ฆ„์€ private(_) ์ƒ์„ฑ์ž๋กœ๋งŒ ๋งŒ๋“ ๋‹ค๋ฉด, ์–ด๋–ค ์ด๋ฆ„๋„ ์ƒ๊ด€ ์—†๋‹ค. Dart ์–ธ์–ด์—์„œ๋Š” ์ด๋ฆ„ ์—†๋Š” ์ƒ์„ฑ์ž๋ฅผ ์„ ์–ธํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ public ์ƒ์„ฑ์ž๊ฐ€ ๋งŒ๋“ค์–ด์ง€๊ธฐ์— ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ Dart์˜ private์„ ๋งŒ๋“œ๋Š” ์–ธ๋”๋ฐ”(_) ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
์ฐธ๊ณ ๋กœ ์ƒ์„ฑ์ž๋ฅผ public ์ƒ์„ฑ์ž๋กœ ๋งŒ๋“ค๊ฒŒ ๋˜๋ฉด, public ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค(instance)๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ, ์ผ๋ฐ˜ ํด๋ž˜์Šค๊ฐ€ ๋œ๋‹ค.

์ถ”์ƒ(abstract)ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์„ ์‚ฌ์šฉํ•˜๋ฉด, ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด ๊ณ ์ • ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๊ณ , ์—ฌ๋Ÿฌ ์˜์—ญ์—์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ์—๋„, ๋™์ผ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์‹ถ์„ ๋•Œ์—, ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์‹คํ–‰ ๋ถ€ํ„ฐ ์ข…๋ฃŒ๊นŒ์ง€ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์œผ๋กœ ๊ตฌํ˜„๋˜๋Š” ํŒจํ„ด์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๊ณ , ๊ฐ€์šฉ์ƒํƒœ๋กœ ์ „ํ™˜ํ•ด์ฃผ๋Š” GC(Garbage Collector)์˜ ๋Œ€์ƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์‚ด์•„์žˆ๋Š” ์ธ์Šคํ„ด์Šค๋กœ ๋‚จ๊ฒŒ๋œ๋‹ค.

Flutter ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด, ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์€ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ณธ์ ์ธ ํŒจํ„ด์ด๊ธฐ์— ์•Œ์•„๋‘๋ฉด ๋ถ„๋ช…ํžˆ ์‚ฌ์šฉ ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

callable

Callable objects

To allow an instance of your Dart class to be called like a function, implement the call() method.

The call() method allows an instance of any class that defines it to emulate a function. This method supports the same functionality as normal functions such as parameters and return types.

Dart ์–ธ์–ด์˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋ฉด์„œ, call ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด์„œ ์‚ฌ์šฉํ•ด ๋ณด์…จ๊ฑฐ๋‚˜ ๋“ค์–ด๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.

call ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค(class)์˜ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ํ•จ์ˆ˜ ์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ์ด๊ณ , ์ผ๋ฐ˜ ํ•จ์ˆ˜์™€ ๋™์ผํ•˜๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜, ๋ฐ˜ํ™˜ ํƒ€์ž…๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค.

์ธ์Šคํ„ด์Šค๋ฅผ ํ•จ์ˆ˜ ์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์–ด๋–ค ์˜๋ฏธ์ผ๊นŒ ?

User ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  call ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ ํ•˜๋Š”๋ฐ, ๋งค๊ฐœ๋ณ€์ˆ˜ name์„ ์ž…๋ ฅ ๋ฐ›์•„ ๋ฌธ์ž์—ด(String)์„ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋„๋ก ํ•ด์ฃผ์ž.

class User {
  String call(String name) => "์‚ฌ์šฉ์ž ์ด๋ฆ„์€ $name ์ž…๋‹ˆ๋‹ค";
}

User ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค user๋ฅผ ํ•จ์ˆ˜ ํ˜•ํƒœ๋กœ ํ˜ธ์ถœ์„ ํ•ด๋ณด์ž. ๊ฒฐ๊ณผ๋Š” ์ •์ƒ์ ์œผ๋กœ call ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผฐ๋‹ค.

void main() {
  User user = User();
  String name = user("Tyger");
  print(name);
  // ์‚ฌ์šฉ์ž ์ด๋ฆ„์€ Tyger ์ž…๋‹ˆ๋‹ค
}

User ํด๋ž˜์Šค์— call ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ์ง€ ์•Š์•˜๋‹ค๋ฉด, ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ? ๋‹น์—ฐํžˆ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ , ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

call ๋ฉ”์„œ๋“œ ๊ตฌํ˜„์‹œ ๋ฉ”์„œ๋“œ ๋„ค์ž„์€ ๋ฐ˜๋“œ์‹œ call() ์ด์–ด์•ผ ํ•˜๊ณ , call ๋ฉ”์„œ๋“œ๋Š” ํ•œ ๊ฐœ๋งŒ ๋“ฑ๋ก์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ƒ์† ๊ด€๊ณ„์ธ ๊ฒฝ์šฐ ํด๋ž˜์Šค ๋งˆ๋‹ค ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ call ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ผ๋ฐ˜ ํ•จ์ˆ˜์™€ ๋™์ผํ•˜๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜, ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Calculator {
  int call(int a, int b, int c) => a + b + c;
}

void main() {
  Calculator calculator = Calculator();
  int add = calculator(20, 3, 45);
  print(add);
  // 68
}

User ํด๋ž˜์Šค์— ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ name์„ ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋ก ํ•˜์ž.

class User {
  final String name;
  const User(this.name);
}

User ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ถœ๋ ฅํ•ด๋ณด๋ฉด, "Instance of 'User'" ๋ผ๊ณ  ์ถœ๋ ฅ์ด ๋˜๋Š”๋ฐ, call ๋ฉ”์„œ๋“œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

void main() {
  User name = User("Tyger");
  print(name);
  // Instance of 'User'
}

call ๋ฉ”์„œ๋“œ์— ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž.

class User {
  final String name;

  const User(this.name);
  void call() => print(name);
}

์ธ์Šคํ„ด์Šค ๋„ค์ž„์„ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

void main() {
  User name = User("Tyger");
  name();
  // Tyger
}

์ด๋ฒˆ์—๋Š” ์ข€ ๋” ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•ด call ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์ž.

DateTime ํƒ€์ž…์œผ๋กœ ๋‚ ์งœ๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ ์›ํ•˜๋Š” ํ˜•ํƒœ๋กœ ํฌ๋งทํŒ… ํ›„ ๋ฌธ์ž์—ด(String) ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” call ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๋„๋ก ํ•˜๊ฒ ๋‹ค.

class Watch {
  String call(DateTime date) {
    return "${date.month.toString().padLeft(2, "0")}์›” ${date.day.toString().padLeft(2, "0")}์ผ, ${date.year}๋…„";
  }
}

watch ์ธ์Šคํ„ด์Šค๋ฅผ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•ด ๋ณด๋ฉด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

void main() {
  Watch watch = Watch();
  String message = watch(DateTime(2000, 1, 1));
  print(message);
  // 01์›” 01์ผ, 2000๋…„
}

call ๋ฉ”์„œ๋“œ๋Š” ์ฃผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์€ ์•„๋‹ˆ์ง€๋งŒ ์ƒ์† ๊ด€๊ณ„์˜ ํด๋ž˜์Šค ๊ณ„์ธต์—์„œ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฐ ์œ ์—ฐ์„ฑ์„ ๋†’ํž ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ๋„ ํ•˜๋‹ˆ call ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅ ํ•˜๋‹ค๋Š” ๋ถ€๋ถ„์€ ๊ธฐ์–ตํ•˜์‹œ๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ด๋‹ค.

JSON Serializable

ํด๋ž˜์Šค(class)๋ฅผ ๋‹ค๋ฃฐ ๋•Œ์— ์ž์ฃผ ์–ธ๊ธ‰๋˜๊ณ  ์„ ์–ธ๋˜๋Š” ๋‚ด์šฉ์˜ ์ฝ”๋“œ๊ฐ€ ๋ฐ”๋กœ JSON ์ง๋ ฌํ™”(serialize)์ด๋‹ค.

JSON์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์•Œ๊ธฐ ์œ„ํ•ด์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ REST API์— ๋Œ€ํ•œ ๊ฐœ๋…๋„ ์„ ํ–‰ ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ์ง๋ ฌํ™”๋ฅผ ์œ„ํ•œ Dart ํด๋ž˜์Šค ๊ฐœ๋… ๋ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์— ์ง‘์ค‘ํ•ด์„œ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๋‹ค.

JSON์ด๋ž€, JavaScriptObjectNotation์˜ ์•ฝ์ž๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด ํ‘œ๊ธฐ๋ฒ• ์ด๋ผ๊ณ  ํ•ด์„ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹  ๋ฐ›์„๋•Œ์— JSON ๊ตฌ์กฐ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ฒŒ ๋œ๋‹ค.

JSON ๊ตฌ์กฐ๋Š” key-value ํ˜•ํƒœ์˜ ๊ตฌ์กฐ๋กœ Dart ์–ธ์–ด์˜ Map ํƒ€์ž…๊ณผ ๋น„์Šทํ•œ ๊ตฌ์กฐ์ด๋‹ค.

๋ชจ๋ฐ”์ผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ REST API๋กœ ์„œ๋ฒ„์™€ ํ†ต์‹ ์„ ํ•  ๋•Œ์—, JSON ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฌผ๋ก  JSON ์™ธ์—๋„ xml ๊ตฌ์กฐ๋„ ์žˆ๋‹ค.

์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด Object(๊ฐ์ฒด)๋ฅผ JSON ๊ตฌ์กฐ๋กœ ๋ณ€ํ™”ํ•˜๋Š” ๊ณผ์ •์„ ์ง๋ ฌํ™”(serialization)๋ผ๊ณ  ํ•˜๊ณ  ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹  ๋ฐ›์•„ JSON ๊ตฌ์กฐ๋ฅผ Object(๊ฐ์ฒด)๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ์—ญ์ง๋ ฌํ™”(deSerialization)๋ผ๊ณ  ํ•œ๋‹ค.

Flutter์—์„œ JSON ์ง๋ ฌํ™”๋ฅผ ๋” ์‰ฝ๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ํด๋ž˜์Šค ๊ตฌ์กฐ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ Code Generator๋ฅผ ์‚ฌ์šฉํ•ด ์ž๋™์œผ๋กœ ์„ ์–ธํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด์„œ๋„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
ํ•˜์ง€๋งŒ ์–ด๋–ค ๊ณผ์ •์œผ๋กœ JSON ์ง๋ ฌํ™”๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฐœ๋… ์ •๋„๋Š” ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•˜๊ณ , ์‹ฌ์ง€์–ด๋Š” ํŒจํ‚ค์ง€ ์—†์ด๋„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํŒจํ‚ค์ง€๋ฅผ ๋” ์ž˜ ์‚ฌ์šฉํ•˜๊ณ  ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋จผ์ €, Dart ๊ฐ์ฒด(object)๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด JSON์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜์ž.

ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด๋ณด๋„๋ก ํ•˜์ž.

class Person {
  final int id;
  final String name;
  final DateTime birthday;
  final bool gender;

  const Person({
    required this.id,
    required this.name,
    required this.birthday,
    required this.gender,
  });
}

๊ฐ์ฒด(object)๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์ž.

toJson ๋ฉ”์„œ๋“œ๋ฅผ ์„ ์–ธํ•ด์ฃผ์ž

class Person {
	...
  Map<String, dynamic> toJson() {
    return {};
  }
}

toJson ๋ฉ”์„œ๋“œ์•ˆ์— ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ Dart key-value ๊ตฌ์กฐ์ธ Map ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

  Map<String, dynamic> toJson() {
    return {
      "id": id,
      "name": name,
      "birthday": birthday,
      "gender": gender,
    };
  }

Person ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•œ toJson ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด JSON ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

void main() {
  Person person = Person(
    id: 0,
    name: "tyger",
    birthday: DateTime(2000, 1, 1),
    gender: true,
  );
  Map<String, dynamic> data = person.toJson();
  print(data);
}

์—ฌ๊ธฐ์„œ Person ํด๋ž˜์Šค์•ˆ์— ๊ฐ์ฒด(object) ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

์ฃผ์†Œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Address ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

class Address {
  final int postCode;
  final String address;
  final String detail;

  const Address({
    required this.postCode,
    required this.address,
    required this.detail,
  });
}

Person ํด๋ž˜์Šค์— Address ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , toJson ๋ฉ”์„œ๋“œ์—๋„ address ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

class Person {
  final int id;
  final String name;
  final DateTime birthday;
  final bool gender;
  final Address address;

  const Person({
    required this.id,
    required this.name,
    required this.birthday,
    required this.gender,
    required this.address,
  });

  Map<String, dynamic> toJson() {
    return {
      "id": id,
      "name": name,
      "birthday": birthday,
      "gender": gender,
      "address" : address,
    };
  }
}

๋‹ค์‹œ toJson ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ด ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ? ์ „์†ก์— ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์ด์ง€๋งŒ, ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ Address ๊ฐ์ฒด๋ฅผ JSON ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜์ง€ ์•Š๊ณ , ๊ฐ์ฒด(object) ์ž์ฒด๊ฐ€ ์ „์†ก์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

void main() {
  Person person = Person(
    id: 0,
    name: "tyger",
    birthday: DateTime(2000, 1, 1),
    gender: true,
    address: Address(
        postCode: 15000, address: "๋Œ€ํ•œ๋ฏผ๊ตญ ์„œ์šธํŠน๋ณ„์‹œ ...", detail: "XX์•„ํŒŒํŠธ 101๋™ 101ํ˜ธ"),
  );
  Map<String, dynamic> data = person.toJson();
  print(data);
}

Address ํด๋ž˜์Šค์—๋„ toJson ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž.

class Address {
	...
  Map<String, dynamic> toJson() {
    return {
      "postCode": postCode,
      "address": address,
      "detail": detail,
    };
  }
}

์ด์ œ Person ํด๋ž˜์Šค์˜ toJson ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

  Map<String, dynamic> toJson() {
    return {
      "id": id,
      "name": name,
      "birthday": birthday,
      "gender": gender,
      "address": address.toJson(),
    };
  }

์ด๋ฒˆ์—๋Š” ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ์— JSON ๊ตฌ์กฐ๋ฅผ ๊ฐ์ฒด(object)๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ๋‹ค.

๊ณต์žฅ์—์„œ ์ฃผ๋ฌธ์„ ๊ด€๋ฆฐํ•˜๊ธฐ ์œ„ํ•œ Order ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด๋ณด์ž.

class Order {
  final int id;
  final String name;
  final DateTime orderAt;
  final bool isPreOrder;

  const Order({
    required this.id,
    required this.name,
    required this.orderAt,
    required this.isPreOrder,
  });
}

์ด์ œ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ ๋ฐ›๋Š” JSON ๊ตฌ์กฐ๊ฐ€ ๊ฐ์ฒด(object)๋กœ ๋ณ€ํ™˜๋  ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฏธ ์ƒ์‚ฐ๋œ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŒฉํ† ๋ฆฌ(factory) keyword๋ฅผ ์‚ฌ์šฉํ•ด fromJson ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋ก ํ•˜์ž.

toJson ๋ฉ”์„œ๋“œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ fromJson ๋ฉ”์„œ๋“œ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์ „์†ก ๋ฐ›์€ JSON ๊ตฌ์กฐ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

class Order {
	...
  factory Order.fromJson(Map<String, dynamic> json) => null;
}

JSON ๊ตฌ์กฐ๋ฅผ Map ํƒ€์ž…์œผ๋กœ ๋ฐ›์•„์˜จ ํ›„ ๊ฐ์ฒด(object)๋กœ ์ธ์Šคํ„ด์Šค(instance)๋ฅผ ๋ฐ˜ํ™˜ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

  factory Order.fromJson(Map<String, dynamic> json) {
    return Order(
      id: json["id"],
      name: json["name"],
      orderAt: json["orderAt"],
      isPreOrder: json["isPreOrder"],
    );
  }

์ด์ œ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ ๋ฐ›์€ JSON ๋ฐ์ดํ„ฐ๋ฅผ fromJson์„ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด(obejct)๋กœ ๋ณ€ํ™˜ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

void main() {
  Order order = Order.fromJson(data);
  print(order);
}

Car ํด๋ž˜์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์ฃผ๊ณ , Order ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€ํ•ด ์ฃผ์ž.

class Car {
  final String name;
  final int colorType;

  const Car({required this.name, required this.colorType});

  factory Car.fromJson(Map<String, dynamic> json) {
    return Car(
      name: json["name"],
      colorType: json["colorType"],
    );
  }
}

์ถ”๊ฐ€ํ•œ Car ํด๋ž˜์Šค๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†๋‹ค. ์ด์œ ๋Š” ์ด๋ฏธ toJson ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋ฉด์„œ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค. Car ํด๋ž˜์Šค๋„ ๋™์ผํ•˜๊ฒŒ fromJson ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

class Order {
	...
  final Car car;

  const Order({
	...
    required this.car,
  });

  factory Order.fromJson(Map<String, dynamic> json) {
    return Order(
      id: json["id"],
      name: json["name"],
      orderAt: json["orderAt"],
      isPreOrder: json["isPreOrder"],
      car: json["car"],
    );
  }
}

JSON์€ Dart Map ํƒ€์ž…์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— as ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด Map ํƒ€์ž… ๋ณ€ํ™˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ fromJson ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

  factory Order.fromJson(Map<String, dynamic> json) {
    return Order(
      id: json["id"],
      name: json["name"],
      orderAt: json["orderAt"],
      isPreOrder: json["isPreOrder"],
      car: Car.fromJson(json["car"] as Map<String, dynamic>),
    );
  }

์ด๋ฒˆ์—” ๋ฐฐ์—ด์„ ์–ด๋–ป๊ฒŒ JSON์—์„œ ๊ฐ์ฒด(object)๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

Car ํด๋ž˜์Šค๋ฅผ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝํ•ด ๋ณด์ž. ์ด์ œ ์•ž์„œ ์ž‘์„ฑํ•œ fromJson ๋ฉ”์„œ๋“œ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

class Order {
	...
  final List<Car> cars;

  const Order({	
	...
    required this.cars,
  });
}

๋ฆฌ์ŠคํŠธ ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌ ๋ฐ›๋Š” JSON ๊ตฌ์กฐ๋Š” ๋ฐฐ์—ด ์•ˆ์— ๋‹ด๊ธด ๊ฐ๊ฐ์˜ JSON ๊ตฌ์กฐ๋ฅผ map ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ์ˆœํ™˜์ ์œผ๋กœ ๊ฐ์ฒด(object)๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ํŒŒ์‹ฑํ•˜๋ฉด ๋œ๋‹ค.

  factory Order.fromJson(Map<String, dynamic> json) {
    return Order(
		...
      cars: List<Car>.from(json["cars"])
          .map((e) => Car.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }

getter ? setter ?

ํด๋ž˜์Šค(class)๋ฅผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” getter, setter์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

getter, setter์— ๋Œ€ํ•ด ์‚ดํŽด ๋ณด๊ธฐ์ „ ์ ‘๊ทผ ์ง€์ •์ž์— ๋Œ€ํ•ด์„œ ์•Œ์•„์•ผ ํ•œ๋‹ค.

Dart ์–ธ์–ด์—์„œ ํด๋ž˜์Šค(class)์˜ ๋ฉค๋ฒ„๋ฅผ ์„ ์–ธํ•  ๋•Œ์—๋Š” ๋ฉค๋ฒ„์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ์ง€ ๋ถˆ๊ฐ€๋Šฅํ•œ์ง€์— ๋Œ€ํ•ด ์ ‘๊ทผ์˜ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋Š” ์ ‘๊ทผ ์ง€์ •์ž๊ฐ€ ์žˆ๋‹ค.
Dart ์–ธ์–ด์—์„œ ์ ‘๊ทผ ์ง€์ •์ž๋Š” private, public ๋‘ ๊ฐ€์ง€์˜ ๊ฐœ๋…์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, private์œผ๋กœ ๋ฉค๋ฒ„๋ฅผ ์„ ์–ธํ•˜๊ฒŒ ๋˜๋ฉด ๋™์ผ ํŒŒ์ผ ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค.

private์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์–ธ๋”์Šค์ฝ”์–ด(_)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , ๊ทธ ์™ธ์˜ ๋ชจ๋“  ๋ฉค๋ฒ„๋Š” public์ด ๋œ๋‹ค.

์ด์–ด์„œ ๊ฐ์ฒด ์ง€ํ–ฅ์˜ 4๊ฐ€์ง€ ์ค‘์š”ํ•œ ํŠน์ง•๋„ ๊ฐ€๋ณ๊ฒŒ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

  • ์ถ”์ƒํ™”
  • ์บก์Šํ™”
  • ์ƒ์†
  • ๋‹คํ˜•์„ฑ

์ง€๊ธˆ๊นŒ์ง€ ํด๋ž˜์Šค(class)์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋ฉด์„œ, ๊ฐ์ฒด ์ง€ํ–ฅ์˜ ํŠน์ง•์— ๋Œ€ํ•ด์„œ๋Š” ์‚ดํŽด๋ณด์ง€ ์•Š์•˜์—ˆ๋‹ค. ๊ฐ์ฒด ์ง€ํ–ฅ์˜ ํŠน์ง•์„ ์„ค๋ช… ํ•˜๊ธฐ์—๋Š” ๊ธ€์˜ ๋‚ด์šฉ์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ ๋‹ค๋ฃจ์ง€ ์•Š์•˜์—ˆ์ง€๋งŒ, getter, setter๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ํŠน์ง• ์ค‘ ์บก์Šํ™”์™€ ์ •๋ณด ์€๋‹‰์˜ ๊ฐœ๋…์€ ์„ค๋ช…ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

์บก์Šํ™”๋ž€ ์—ฐ๊ด€๋œ ๋ชฉ์ ์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด(object)์˜ ์†์„ฑ(attribute)์ด๋‚˜ ๋™์ž‘(behavior)์„ ํ•˜๋‚˜์˜ ์ง‘ํ•ฉ์œผ๋กœ ์ ์ ˆํžˆ ๋ฌถ๋Š”๋‹ค๋Š” ๊ฐœ๋…์ด๊ณ , ์ •๋ณด ์€๋‹‰์ด๋ž€ ์ด๋ ‡๊ฒŒ ๋ฌถ์ธ ํด๋ž˜์Šค(class)์˜ ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ํ•จ๋ถ€๋กœ ๊ณต๊ฐœํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฐœ๋…์ด๋‹ค.

public์œผ๋กœ ์„ ์–ธ๋˜๋ฉด, ์•„๋ฌด ๊ณณ์—์„œ๋‚˜ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด ์ง€ํ–ฅ์˜ ์บก์Šํ™”์— ๋”ฐ๋ผ ์ •๋ณด๋ฅผ private์„ ์‚ฌ์šฉํ•ด ์€๋‹‰ํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋„๋ก ํ•˜๊ฒŒ๋œ๋‹ค.

private์˜ ๋ฉค๋ฒ„๋ฅผ ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์„๊นŒ ?

์ด๊ฑธ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ๋ฐ”๋กœ getter์™€ setter์ด๋‹ค.
์ด๋ฆ„๋งŒ์œผ๋กœ ์ง์ž‘ํ•ด๋„ ์–ด๋–ค ๊ธฐ๋Šฅ์ธ์ง€๋Š” ๋Œ€์ถฉ ์•Œ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

getter๋Š” ํด๋ž˜์Šค(class)์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜(MemberVaribale)๋ฅผ ๊ฒ€์ƒ‰ ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๊ณ  Dart์—์„œ๋Š” get ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ณ , setter๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜(MemberVaribale)๋ฅผ ๋ณ€๊ฒฝ ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

getter, setter๋Š” ํด๋ž˜์Šค(class) ๋‚ด์˜ ๋ฉค๋ฒ„์— ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ ์ ‘๊ทผ ์ง€์ •์ž๊ฐ€ ํด๋ž˜์Šค์— ์ข…์†๋  ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Dart ์—์„œ๋Š” ๋™์ผ ํŒŒ์ผ ๋‚ด์—์„œ๋Š” private์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

MotoCycle ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๋ณ€์ˆ˜ name์„ ์–ธ๋”์Šค์ฝ”์–ด(_)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ private๋กœ ์ƒ์„ฑํ•ด์ฃผ์ž.

class MotoCycle {
  final String _name;
  const MotoCycle(this._name);
}

์ด์ œ MotoCycle ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šค ํ•ด์ฃผ๊ณ , ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด private ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•œ _name์— ์ ‘๊ทผํ•ด๋ณด์ž.

void main() {
  MotoCycle vehicle = MotoCycle("R1");
  print(vehicle._name);
}

์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

The getter '_name' isn't defined for the type 'MotoCycle'.
Try importing the library that defines '_name', correcting the name to the name of an existing getter, or defining a getter or field named '_name'.

get ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด getter๋ฅผ ๋“ฑ๋กํ•ด์ฃผ์ž.

class MotoCycle {
  final String _name;
  const MotoCycle(this._name);

  String get name => _name;
}

์ด์ œ ๋‹ค์‹œ MotoCycle ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ _name์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ getter์— ์„ ์–ธํ•œ name์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉด ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

void main() {
  MotoCycle vehicle = MotoCycle("R1");
  print(vehicle.name);
}

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด ๋ฉค๋ฒ„๋ณ€์ˆ˜์™€ getter์˜ ๋„ค์ด๋ฐ ๊ทœ์น™์ธ๋ฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ์–ธ๋”์Šค์ฝ”์–ด๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ getter์˜ ๋„ค์ด๋ฐ์€ ์ž์œ ๋กญ๊ฒŒ ์ง€์ •ํ•ด๋„ ์ž‘๋™์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.

String get motoCycleName => _name;

getter์—๋Š” ๋ฐ˜๋“œ์‹œ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋งŒ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
์ด๋ฒˆ์—” brand๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ private์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ , name์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ์— brand ๋ณ€์ˆ˜๋ฅผ ๋ถ™์—ฌ์„œ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ˆ˜์ •ํ•ด ๋ณด์ž.

class MotoCycle {
  final String _name;
  final String _brand;
  const MotoCycle(this._name, this._brand);

  String get name {
    return "$_brand : $_name";
  }
}

getter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ํด๋ž˜์Šค(class)์˜ ์ •๋ณด๋ฅผ ์›ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

void main() {
  MotoCycle vehicle = MotoCycle("R1", "Yamaha");
  print(vehicle.name);
  // Yamaha : R1
}

getter์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ดค๋Š”๋ฐ, ํ•œ ๊ฐ€์ง€ ์˜๋ฌธ์ ์ด ์ƒ๊ธด๋‹ค.๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ private๋กœ ์„ ์–ธํ•˜์—ฌ ์ •๋ณด์€๋‹‰์„ ํ•˜์˜€์ง€๋งŒ, getter๋ฅผ ์‚ฌ์šฉํ•ด ์–ด๋””์„œ๋“  ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด, ๊ฐ์ฒด์ง€ํ–ฅ์˜ ํŠน์ง•์ธ ์บก์Šํ™”์— ์˜๋ฏธ๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€ ? ์ •๋ณด๊ฐ€ ์€๋‹‰๋˜์—ˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€ ?

์ด๋Ÿฐ ์˜๋ฌธ์ ์ด ๋ฐ”๋กœ getter ์‚ฌ์šฉ์„ ์ง€์–‘ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ•˜๋Š” ์ด์œ ๋‹ค. ์ •๋ณด์€๋‹‰์— ์˜๋ฏธ๊ฐ€ ์—†์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
๋‹จ์ˆœํžˆ ๋ฉค๋ฒ„๋ณ€์ˆ˜์˜ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๊ณ ์ž ํ•  ๋•Œ์—๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ๋ฌด๋ถ„๋ณ„ํ•œ getter์‚ฌ์šฉ์€ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์ด์–ด์„œ setter์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.
์ €๋Š” setter ๋ฅผ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด์œ ์— ๋Œ€ํ•ด์„œ๋Š” ์šฐ์„  setter๊ฐ€ ๋ญ”์ง€์— ๋Œ€ํ•ด์„œ ๋ถ€ํ„ฐ ํ™•์‹คํžˆ ์•Œ๊ณ  ์„ค๋ช…ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

setter๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•  ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.
setter์™€ getter๋Š” ์ค‘๋ณต๋œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” getter์˜ ๋„ค์ด๋ฐ ๊ทœ์น™์„ ๋”ฐ๋ผ์„œ ์ƒ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.

set ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•˜๋Š” ์ƒํƒœ๋ฅผ ๋ฐ›์•„์™€ ๋ฉค๋ฒ„๋ณ€์ˆ˜์— ํ• ๋‹นํ•ด์ฃผ๋ฉด ๋˜๋Š” ๊ฐ„๋‹จํ•œ ๊ตฌ์กฐ์ด๋‹ค.

class MotoCycle {
  String _name;
  MotoCycle(this._name);

  String get name => _name;
  set name(String value) => _name = value;
}

setter ์‚ฌ์šฉ์€ public์œผ๋กœ ์ƒ์„ฑ๋œ ๋ฉค๋ฒ„๋ณ€์ˆ˜์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•  ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

void main() {
  MotoCycle vehicle = MotoCycle("R1");
  print(vehicle.name);
  // R1

  vehicle.name = "R6";
  print(vehicle.name);
  // R6
}

setter์˜ ๊ธฐ๋Šฅ ๋ฐ ์—ญํ• ์€ ์•Œ์•˜์œผ๋‹ˆ, ์™œ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•ด์•ผ ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

์šฐ์„  setter ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” ์ƒ์ˆ˜(final)๋กœ ์„ ์–ธํ•  ์ˆ˜๊ฐ€ ์—†๊ณ , ๋ฌด์—‡๋ณด๋‹ค ์ค‘์š”ํ•œ ์ ์€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•˜๋Š” ์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๊ฒŒ ๋œ๋‹ค.
์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ๊ฐ€ ์™œ ? ์–ด๋–ป๊ฒŒ ? ์–ด๋””์„œ ? ๋ณ€๊ฒฝ์„ ์‹œ๋„ํ–ˆ๋Š”์ง€ ํŒŒ์•…์„ ํ•˜๊ธฐ ์œ„ํ•ด ์—ญ์ถ”์ ์„ ํ•ด์•ผ๋งŒ ํ•œ๋‹ค.
๋˜ ํ•˜๋‚˜์˜ ๋ฌธ์ œ๋Š” ๊ฐ์ฒด(object)์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ด ๋ถ€๋ถ„์€ getter์˜ ๋ฌธ์ œ์ ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๋กœ ๋ชจ๋“  ์˜์—ญ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

getter, setter์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ดค๋Š”๋ฐ, ์ง€์–‘ํ•˜๋ผ๋Š” ๊ฒƒ์€ ๋‚จ๋ฐœํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด์ง€ ์•„์˜ˆ ์‚ฌ์šฉ ์ž์ฒด๋ฅผ ํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ์•„๋‹ˆ๋‹ค.

ํ•„์š”์— ์˜ํ•ด์„œ ๋‹น์—ฐํžˆ getter, setter๊ฐ€ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์€ ์žˆ๋‹ค.

์ถ”๊ฐ€๋กœ Dart ํด๋ž˜์Šค(class)๋Š” ๋ฉค๋ฒ„๋ณ€์ˆ˜์— ๋Œ€ํ•ด ์•”๋ฌต์ ์œผ๋กœ getter, setter๊ฐ€ ์ƒ์„ฑ์ด ๋˜๊ณ , ๋ฉค๋ฒ„๋ณ€์ˆ˜๊ฐ€ ์ƒ์ˆ˜์ธ ๊ฒฝ์šฐ์—” getter๋งŒ ์ƒ์„ฑ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์—, private์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ณ„๋„๋กœ getter, setter๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜์Œ์—๋„ ๋ฉค๋ฒ„๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด์—ˆ๋‹ค.

copyWith

setter๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด(object)์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ดค์—ˆ๋‹ค.

setter ์‚ฌ์šฉ์‹œ ์ƒ์ˆ˜(final)๋กœ ์„ ์–ธํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค๊ณ  ์•ž์„œ ์–ธ๊ธ‰ ํ–ˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์„ setter ์‚ฌ์šฉ์„ ์ง€์–‘ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜๋กœ ์„ค๋ช… ํ•˜๊ธฐ๋„ ํ•˜์˜€๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด, ์™œ ์ƒ์ˆ˜(final)๋กœ ์„ ์–ธ ๋˜์–ด์•ผ ํ•˜๊ณ , ์ƒ์ˆ˜(final)๋กœ ์„ ์–ธ๋œ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์„๊นŒ ?
์ด์ œ setter์— ๋Œ€ํ•œ ๋ถ€๋ถ„์€ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ๋ฉค๋ฒ„๋ฅผ public์œผ๋กœ ์ƒ์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

User ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , name ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•ด๋ณด์ž.

class User {
  final String name = "tyger";
}

๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋‹น์—ฐํ•œ ๊ฒƒ์ด๋‹ค.
์ƒ์ˆ˜(final)๋กœ ์„ ์–ธ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.

void main() {
  User tyger = User();
  tyger.name = "TYGER";
}

'name' can't be used as a setter because it's final. Try finding a different setter, or making 'name' non-final.

๊ทธ๋ ‡๋‹ค๋ฉด ์ƒ์ˆ˜๋กœ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ฉด ์•ˆ๋˜๋‚˜ ? ๊ทธ๋Ÿผ ์‰ฝ๊ฒŒ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์ œ์–ดํ•  ์ˆ˜ ์žˆ์„ ํ…๋ฐ...

Dart ์–ธ์–ด๋‚˜ Flutter์—์„œ๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด(Immutable Object)๋ฅผ ์ƒ์„ฑํ•ด ํผํฌ๋จผ์Šค ํ–ฅ์ƒ ๋ฐ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋™์ž‘์„ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฒ„๊ทธ๋ฅผ ๊ฐ์†Œ ์‹œํ‚ค๊ณ , ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’ํž ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ  ์žˆ๋‹ค.

๋ณ€ํ•  ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด, ์ฆ‰ ๋ถˆ๋ณ€ ๊ฐ์ฒด(Immutable Object)๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์ˆ˜(final) ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
์ƒ์ˆ˜(final) ํƒ€์ž…์€ ์ธ์Šคํ„ด์Šค ํ›„์— ๊ฐ์ฒด์˜ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ถˆ๋ณ€ ๊ฐ์ฒด(Immutable Object)์˜ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.
์ด๋ ‡๊ฒŒ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌ(copy)ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊นŠ์€๋ณต์‚ฌ(deepCopy)๋ผ ํ•˜๊ณ , copyWith ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

name, age ์†์„ฑ์„ ์ƒ์ˆ˜(final)๋กœ ์„ ์–ธํ•˜์—ฌ User ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž.

class User {
  final String name;
  final int age;

  const User(this.name, this.age);
}

์ด์ œ age ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๊นŠ์€๋ณต์‚ฌ(deepCopy)์ธ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

void main() {
  User tyger = User("tyger", 100);
  tyger = User(tyger.name, 90);
}

์†์„ฑ์ด ์ •์ƒ์ ์œผ๋กœ ๋ณ€๊ฒฝ์ด ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ญ”๊ฐ€ ๋ถˆํŽธํ•˜๋‹ค. ์ง€๊ธˆ์€ ์†์„ฑ์ด 2๊ฐœ ๋ฟ์ด์ง€๋งŒ 10๊ฐœ๋ผ๋ฉด ์ฝ”๋“œ๋งŒ ๋Š˜์–ด๋‚˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

๊นŠ์€๋ณต์‚ฌ(deepCopy)๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” copyWith ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋กํ•˜์ž.

User ํด๋ž˜์Šค์˜ ์†์„ฑ๋“ค์„ nullable ํƒ€์ž…์œผ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ null์ด๋ฉด User ํด๋ž˜์Šค์˜ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , null์ด ์•„๋‹ˆ๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ์ž(constructor)๋กœ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

  User copyWith({
    final String? name,
    final int? age,
  }) {
    return User(
      name ?? this.name,
      age ?? this.age,
    );
  }

์ด์ œ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด copyWith ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์›ํ•˜๋Š” ์†์„ฑ์˜ ๊ฐ’์„ ์ „๋‹ฌํ•ด ์ฃผ๋ฉด ๋ณ€๊ฒฝ๋œ ์†์„ฑ์œผ๋กœ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

void main() {
  User tyger = User("tyger", 100);
  tyger = tyger.copyWith(age: 20);
}

copyWith์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธํ•ด๋ณด์ž. hashCode ๊ฐ’์„ ์ถœ๋ ฅํ•ด๋ณด๋ฉด, copyWith์—์„œ ๋ฐ˜ํ™˜ํ•œ ์ธ์Šคํ„ด์Šค๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

void main() {
  User tyger = User("tyger", 100);
  print(tyger.hashCode);
  // 613218385
  
  tyger = tyger.copyWith(age: 20);
  print(tyger.hashCode);
  // 436920219
}

์ธ์Šคํ„ด์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ํ• ๋‹น๋œ ๊ฒƒ์ธ๋ฐ, ๋ถˆ๋ณ€ ๊ฐ์ฒด(Immutable Object)๋Š” ๋™์ผ ์ธ์Šคํ„ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค ์˜์—ญ์— ๊ฐ์ฒด(object)๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ฐœ๋…์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ๋˜๋ฉด, ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ž์ฃผ ํ• ๋‹น๋ฐ›๊ฒŒ ๋˜๋Š” ๊ฒƒ ์•„๋‹๊นŒ ? ๋งž๋‹ค. ๊นŠ์€๋ณต์‚ฌ(deepCopy)๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์‚ฌ๋ฅผ ํ•˜๊ฒŒ๋˜๋ฉด, ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ƒˆ๋กœ ํ• ๋‹น ๋ฐ›๊ณ  ๊ธฐ์กด ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ๋Š” GC(GarbageCollector) ์˜์—ญ์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.
์ด๋Ÿฐ ๋™์ž‘์ด ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ์˜ ํ• ๋‹น ๋ฐ ๋ฐ˜ํ™˜์ด ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•˜์—ฌ ์ˆœ๊ฐ„์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.
๋˜ํ•œ ๊นŠ์€๋ณต์‚ฌ(deepCopy)๋Š” ๊ฐ์ฒด(object)๋ฅผ ์ „๋ถ€ ๋ณต์‚ฌํ•˜๋Š” ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ์ฒด ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•˜๊ฒŒ ๋˜๋ฉด ์†๋„ ์ €ํ•˜๊ฐ€ ์ง€์†์ ์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๊นŠ์€๋ณต์‚ฌ(deepCopy)์™€ ๊ด€๋ จํ•ด์„œ๋Š” ์ธ์Šคํ„ด์Šค, ์–•์€๋ณต์‚ฌ(shallowCopy), ๊ฐ์ฒด ๋™๋“ฑ์„ฑ ๋“ฑ์˜ ์ถ”๊ฐ€์ ์œผ๋กœ ๋‹ค๋ค„์•ผ ํ•˜๋Š” ๊ฐœ๋…์ด ๋งŽ์•„ ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๊ฐ„๋‹จํ•œ ๊ฐœ๋… ์ •๋„๋งŒ ์ดํ•ดํ•˜๊ณ , ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ณ„๋„๋กœ ๊ธ€์„ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

copyWith๋Š” nullable ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ๋–„๋ฌธ์—, null ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๋ฐ, ์•„๋ž˜ ๊ณต์œ ํ•œ ๊ฒŒ์‹œ๊ธ€ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋‹ค์–‘ํ•œ copyWith์— ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

copyWith์— NULL ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

๋งˆ๋ฌด๋ฆฌ

Dart ์–ธ์–ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค(class)์— ๋Œ€ํ•ด ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ๋ถ€ํ„ฐ, ์ถ”์ƒํ™”, ์ƒ์†, ๋””์ž์ธ ํŒจํ„ด ๋ฐ ํด๋ž˜์Šค์—์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด์•˜๋‹ค.

์ž์„ธํžˆ ๋‹ค๋ค„๋ณธ ๊ธฐ๋Šฅ๋„ ์žˆ๊ณ , ๊นŠ๊ฒŒ ๋“ค์–ด๊ฐ€๋ฉด ๋‚ด์šฉ์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ ์–ด์ฉ” ์ˆ˜ ์—†์ด ๊ฐœ๋…๋งŒ ์‚ดํŽด๋ณธ ๊ธฐ๋Šฅ๋„ ์žˆ์—ˆ๋‹ค. ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด ์ž์„ธํ•œ ์„ค๋ช…์ด ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋“ค์€ ๋ณ„๋„๋กœ ๋‚ด์šฉ์— ๋Œ€ํ•ด ๊ธ€์„ ์ž‘์„ฑํ•  ์˜ˆ์ •์ด๋‹ค.

ํด๋ž˜์Šค๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ๋‹น์—ฐํžˆ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€๋งŒ, ๊ฐœ๋… ์ •๋„๋งŒ ์•Œ๊ณ  ์žˆ๋”๋ผ๋„ ํ•„์š”์‹œ์— ์ ์ ˆํžˆ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ๋งŒ ์ž์„ธํžˆ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉด ๋œ๋‹ค. ์–ต์ง€๋กœ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์™ธ์šธ ํ•„์š”๋Š” ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
์ž์ฃผ ๋‹ค๋ค„๋ณด๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ต์ˆ™ํ•ด ์งˆ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๋“ค์ด๋‹ค.

ํด๋ž˜์Šค์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•˜์‹œ๊ฑฐ๋‚˜ ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์ง€ ์•Š์œผ์‹  ๋‚ด์šฉ๋“ค์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค

profile
Flutter Developer

0๊ฐœ์˜ ๋Œ“๊ธ€