๐Ÿ“š Today I Learned 11ํšŒ์ฐจ - Dart with ํ‚ค์›Œ๋“œ ๐Ÿ’ก

9 ๋ถ„ ์†Œ์š”

๐Ÿ“– Dart์˜ with ํ‚ค์›Œ๋“œ

๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ

  • extends(์ƒ์†)์™€ with(๋ฏน์Šค์ธ)์˜ ์ฐจ์ด์  ์ดํ•ดํ•˜๊ธฐ
  • Mixin์˜ ์ •์˜์™€ ์‚ฌ์šฉ๋ฒ• ์ตํžˆ๊ธฐ
  • ์บ์ŠคํŒ…๊ณผ ํƒ€์ž… ๊ฒ€์‚ฌ ์›๋ฆฌ ํŒŒ์•…ํ•˜๊ธฐ
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ๋ฏน์Šค์ธ์˜ ํ™œ์šฉ๋ฒ• ํ•™์Šตํ•˜๊ธฐ

๐Ÿ“š ์ฃผ์š” ๋‚ด์šฉ

โญ extends(์ƒ์†) vs with(๋ฏน์Šค์ธ)

with๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ๋จผ์ € extends(์ƒ์†)์™€์˜ ์ฐจ์ด์ ์„ ์•„๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

1. extends (์ƒ์†) ๐Ÿงฌ

extends๋Š” โ€~์ด๋‹คโ€ (is a) ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋ถ€๋ชจ์™€ ์ž์‹ ๊ด€๊ณ„์ฒ˜๋Ÿผ, ์ž์‹ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋ฌผ๋ ค๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํด๋ž˜์Šค์˜ ๊ทผ๋ณธ์ ์ธ ์ •์ฒด์„ฑ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ์‹œ: class Dog extends Animal { ... }
    • โ€œ๊ฐœ๋Š” ๋™๋ฌผ์ด๋‹ค.โ€ (Dog is an Animal.)
  • ํŠน์ง•: Dart์—์„œ๋Š” ๋‹จ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋งŒ extends ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๋ถ€๋ชจ๋Š” ํ•˜๋‚˜)

2. with (๋ฏน์Šค์ธ) ๐Ÿš€

with๋Š” โ€~๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹คโ€ (can do) ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ƒ์†์ฒ˜๋Ÿผ ์ •์ฒด์„ฑ์„ ๋ฌผ๋ ค๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํŠน์ • ๊ธฐ๋Šฅ(๋Šฅ๋ ฅ)๋งŒ ์™ ๊ฐ€์ ธ์™€์„œ ์žฅ์ฐฉํ•˜๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.

  • ๋น„์œ : ์ž๋™์ฐจ์— โ€˜ํ„ฐ๋ณด ์—”์ง„โ€™์ด๋‚˜ โ€˜๋„ค๋น„๊ฒŒ์ด์…˜โ€™ ๊ฐ™์€ ๋ถ€ํ’ˆ์„ ์ถ”๊ฐ€๋กœ ์žฅ์ฐฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ž๋™์ฐจ์˜ ๋ณธ์งˆ(extends Vehicle)์€ ๋ณ€ํ•˜์ง€ ์•Š์ง€๋งŒ, ์ƒˆ๋กœ์šด ๋Šฅ๋ ฅ(with Turbo, with Navigation)์ด ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด์ฃ .
  • ํŠน์ง•: ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ธฐ๋Šฅ์„ with ํ‚ค์›Œ๋“œ ๋’ค์— ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์žฅ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โšก with ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ๋ฒ•๊ณผ ์˜ˆ์‹œ

with๋Š” ์ด๋ ‡๊ฒŒ โ€˜๊ธฐ๋Šฅ ๋ฉ์–ด๋ฆฌโ€™์ธ Mixin์„ ํด๋ž˜์Šค์— ์ ์šฉํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. โ€˜๋‚  ์ˆ˜ ์žˆ๋Š”โ€™ ๋Šฅ๋ ฅ๊ณผ โ€˜ํ—ค์—„์น  ์ˆ˜ ์žˆ๋Š”โ€™ ๋Šฅ๋ ฅ์„ Mixin์œผ๋กœ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ๋Šฅ๋ ฅ(Mixin) ์ •์˜ํ•˜๊ธฐ mixin ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์žฌ์‚ฌ์šฉํ•  ๊ธฐ๋Šฅ๋“ค์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

// ๋‚˜๋Š” ๋Šฅ๋ ฅ์„ ์ •์˜
mixin CanFly {
  void fly() {
    print("ํ•˜๋Š˜์„ ๋‚ฉ๋‹ˆ๋‹ค. ํ›จํ›จ~");
  }
}

// ํ—ค์—„์น˜๋Š” ๋Šฅ๋ ฅ์„ ์ •์˜
mixin CanSwim {
  void swim() {
    print("๋ฌผ์—์„œ ํ—ค์—„์นฉ๋‹ˆ๋‹ค. ์ฒจ๋ฒ™์ฒจ๋ฒ™!");
  }
}

2. ํด๋ž˜์Šค์— ๋Šฅ๋ ฅ(with) ์žฅ์ฐฉํ•˜๊ธฐ

์ด์ œ ์ด ๋Šฅ๋ ฅ๋“ค์„ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— with ํ‚ค์›Œ๋“œ๋กœ ์žฅ์ฐฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// '์ƒˆ'๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ '๋™๋ฌผ'์ด๋ฉฐ, '๋‚˜๋Š” ๋Šฅ๋ ฅ'์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
class Bird extends Animal with CanFly {
  // Bird ํด๋ž˜์Šค๋Š” ์ด์ œ fly() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
}

// '์˜ค๋ฆฌ'๋Š” '๋™๋ฌผ'์ด๋ฉฐ, '๋‚˜๋Š” ๋Šฅ๋ ฅ'๊ณผ 'ํ—ค์—„์น˜๋Š” ๋Šฅ๋ ฅ'์„ ๋ชจ๋‘ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
class Duck extends Animal with CanFly, CanSwim {
  // Duck ํด๋ž˜์Šค๋Š” ์ด์ œ fly()์™€ swim() ๋ฉ”์†Œ๋“œ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
}

// '๋ฌผ๊ณ ๊ธฐ'๋Š” '๋™๋ฌผ'์ด๋ฉฐ, 'ํ—ค์—„์น˜๋Š” ๋Šฅ๋ ฅ'๋งŒ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
class Fish extends Animal with CanSwim {
  // Fish ํด๋ž˜์Šค๋Š” ์ด์ œ swim() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
}

void main() {
  var duck = Duck();
  duck.fly();   // ์ถœ๋ ฅ: ํ•˜๋Š˜์„ ๋‚ฉ๋‹ˆ๋‹ค. ํ›จํ›จ~
  duck.swim();  // ์ถœ๋ ฅ: ๋ฌผ์—์„œ ํ—ค์—„์นฉ๋‹ˆ๋‹ค. ์ฒจ๋ฒ™์ฒจ๋ฒ™!

  var fish = Fish();
  fish.swim();  // ์ถœ๋ ฅ: ๋ฌผ์—์„œ ํ—ค์—„์นฉ๋‹ˆ๋‹ค. ์ฒจ๋ฒ™์ฒจ๋ฒ™!
  // fish.fly(); // ์—๋Ÿฌ! Fish๋Š” CanFly ๋Šฅ๋ ฅ์ด ์—†์Šต๋‹ˆ๋‹ค.
}

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


๐Ÿ” ์ด์ „ ์„ค๋ช…์— ๋‹ค์‹œ ์ ์šฉํ•ด๋ณด๊ธฐ

์ด์ œ TickerProviderStateMixin ์„ค๋ช…์— ๋‚˜์™”๋˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณด๋ฉด ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class _MyAnimationState extends State<MyAnimation> with TickerProviderStateMixin { ... }

  • extends State<MyAnimation>
    • ์ด ํด๋ž˜์Šค์˜ ์ •์ฒด์„ฑ์€ State์ด๋‹ค. (โ€œ๋‚˜๋Š” MyAnimation์˜ ์ƒํƒœ ๊ฐ์ฒด์ด๋‹ค.โ€)
  • with TickerProviderStateMixin
    • ๊ทธ๋ฆฌ๊ณ  ๋‚˜๋Š” TickerProviderStateMixin์ด ์ œ๊ณตํ•˜๋Š” ๋Šฅ๋ ฅ์„ ์ถ”๊ฐ€๋กœ ์žฅ์ฐฉํ–ˆ๋‹ค. (โ€œ๋‚˜๋Š” Ticker๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.โ€)

๐Ÿ“‹ ํ•ต์‹ฌ ๊ฐœ๋… ์ •๋ฆฌ

๊ตฌ๋ถ„ extends (์ƒ์†) with (๋ฏน์Šค์ธ)
๊ด€๊ณ„ is a (A๋Š” B์ด๋‹ค) can do (A๋Š” B๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค)
๊ฐœ์ˆ˜ ๋‹จ ํ•˜๋‚˜๋งŒ ๊ฐ€๋Šฅ ์—ฌ๋Ÿฌ ๊ฐœ ๊ฐ€๋Šฅ
๋ชฉ์  ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„์˜ ํ•ต์‹ฌ ์ •์ฒด์„ฑ ์ •์˜ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— ๊ฑธ์ณ ์ฝ”๋“œ(๊ธฐ๋Šฅ)๋ฅผ ์žฌ์‚ฌ์šฉ
๋น„์œ  ํ˜ˆ์—ฐ, ๊ฐ€๋ฌธ ๐Ÿงฌ ์Šคํ‚ฌ ์Šต๋“, ์žฅ๋น„ ์žฅ์ฐฉ ๐Ÿš€

๐Ÿ’ป ์‹ค์Šต ๋ฐ ์˜ˆ์ œ

๐Ÿค” ์งˆ๋ฌธ: with์œผ๋กœ ์ƒ์†๋ฐ›์€ ํด๋ž˜์Šค๋กœ casting์€ ์•ˆ๋˜๋Š” ๊ฑธ๊นŒ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋ง์”€๋“œ๋ฆฌ๋ฉด, ๋„ค, ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

with ํ‚ค์›Œ๋“œ๋กœ ์ถ”๊ฐ€๋œ ๋ฏน์Šค์ธ(Mixin)์€ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๊ทธ ๋ฏน์Šค์ธ์˜ ํƒ€์ž…์„ ๊ตฌํ˜„(implements)ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ ๋ฏน์Šค์ธ ํƒ€์ž…์œผ๋กœ ์บ์ŠคํŒ…(ํ˜•๋ณ€ํ™˜)ํ•˜๊ฑฐ๋‚˜ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ’ก with์™€ implements์˜ ์ˆจ๊ฒจ์ง„ ๊ด€๊ณ„

์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด Dart๊ฐ€ with๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class MyClass with MyMixin { ... }

์œ„ ์ฝ”๋“œ๋Š” ์‚ฌ์‹ค์ƒ Dart ๋‚ด๋ถ€์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

class MyClass implements MyMixin { ... }

with๋Š” implements(์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„)์˜ ํŠน๋ณ„ํ•œ ๋ฒ„์ „์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. implements๋Š” โ€œ์ด๋Ÿฐ์ด๋Ÿฐ ๊ธฐ๋Šฅ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์•ฝ์†ํ• ๊ฒŒโ€๋ผ๊ณ  ์„ ์–ธ๋งŒ ํ•˜๋Š” ๊ฒƒ์ด๋ผ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜์ง€๋งŒ, with๋Š” ์„ ์–ธ๊ณผ ๋™์‹œ์— ๋ฏน์Šค์ธ์— ์ด๋ฏธ ์ž‘์„ฑ๋œ ๊ธฐ๋Šฅ๋“ค์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€์„œ ์ž๋™์œผ๋กœ ๊ตฌํ˜„ํ•ด์ค๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ, with MyMixin์„ ์‚ฌ์šฉํ•œ ํด๋ž˜์Šค๋Š” MyMixin์˜ **ํ•˜์œ„ ํƒ€์ž…(subtype)**์ด ๋˜๋ฏ€๋กœ, ํƒ€์ž… ๊ฒ€์‚ฌ(is)์™€ ์บ์ŠคํŒ…(as)์ด ๋ชจ๋‘ ๊ฐ€๋Šฅํ•ด์ง€๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐Ÿ’ป ํƒ€์ž… ์บ์ŠคํŒ… ์‹ค์Šต

์ด์ „ ๋‹ต๋ณ€์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ CanFly, CanSwim ์˜ˆ์ œ๋กœ ์ง์ ‘ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// ๋Šฅ๋ ฅ(Mixin) ์ •์˜
mixin CanFly {
  void fly() => print("ํ•˜๋Š˜์„ ๋‚ฉ๋‹ˆ๋‹ค. ํ›จํ›จ~");
}

mixin CanSwim {
  void swim() => print("๋ฌผ์—์„œ ํ—ค์—„์นฉ๋‹ˆ๋‹ค. ์ฒจ๋ฒ™์ฒจ๋ฒ™!");
}

// '์˜ค๋ฆฌ'๋Š” ๋‚˜๋Š” ๋Šฅ๋ ฅ๊ณผ ํ—ค์—„์น˜๋Š” ๋Šฅ๋ ฅ์„ ๋ชจ๋‘ ๊ฐ€์ง
class Duck with CanFly, CanSwim {}

// ๋น„ํ–‰์„ ์‹œํ‚ค๋Š” ํ•จ์ˆ˜ (CanFly ํƒ€์ž…์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์Œ)
void makeItFly(CanFly flyer) {
  print("${flyer.runtimeType} ๊ฐ์ฒด๊ฐ€ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค.");
  flyer.fly();
}

void main() {
  var duck = Duck();

  // 1. ํƒ€์ž… ๊ฒ€์‚ฌ (is ํ‚ค์›Œ๋“œ)
  // duck์€ CanFly ํƒ€์ž…์ธ๊ฐ€? -> true
  print('duck is CanFly: ${duck is CanFly}');
  // duck์€ CanSwim ํƒ€์ž…์ธ๊ฐ€? -> true
  print('duck is CanSwim: ${duck is CanSwim}');
  // duck์€ String ํƒ€์ž…์ธ๊ฐ€? -> false
  print('duck is String: ${duck is String}');

  print('---');

  // 2. ๋ช…์‹œ์  ์บ์ŠคํŒ… (as ํ‚ค์›Œ๋“œ)
  // duck ๊ฐ์ฒด๋ฅผ CanFly ํƒ€์ž…์œผ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ flyer ๋ณ€์ˆ˜์— ํ• ๋‹น
  CanFly flyer = duck as CanFly;
  flyer.fly();

  print('---');
  
  // 3. ์‹ค์šฉ์ ์ธ ์˜ˆ์‹œ: ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๊ธฐ
  // makeItFly ํ•จ์ˆ˜๋Š” CanFly ํƒ€์ž…์„ ์š”๊ตฌํ•˜๋Š”๋ฐ, duck์€ CanFly์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋ฏ€๋กœ ์ „๋‹ฌ ๊ฐ€๋Šฅ
  makeItFly(duck);
}

์‹คํ–‰ ๊ฒฐ๊ณผ:

duck is CanFly: true
duck is CanSwim: true
duck is String: false
---
ํ•˜๋Š˜์„ ๋‚ฉ๋‹ˆ๋‹ค. ํ›จํ›จ~
---
Duck ๊ฐ์ฒด๊ฐ€ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค.
ํ•˜๋Š˜์„ ๋‚ฉ๋‹ˆ๋‹ค. ํ›จํ›จ~

๐ŸŽฏ ํƒ€์ž… ์บ์ŠคํŒ… ํ•ต์‹ฌ ์ •๋ฆฌ

  • ์บ์ŠคํŒ… ๊ฐ€๋Šฅํ•˜๋‹ค: with๋กœ ์ถ”๊ฐ€ํ•œ ๋ฏน์Šค์ธ์€ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜๋กœ ์ธ์ •๋ฉ๋‹ˆ๋‹ค.
  • ์ด์œ : with๋Š” ๋ฏน์Šค์ธ์„ **๊ตฌํ˜„(implements)**ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„์„œ, ํด๋ž˜์Šค๋Š” ๋ฏน์Šค์ธ์˜ ํ•˜์œ„ ํƒ€์ž…์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  • ํ™œ์šฉ: ์ด ํŠน์ง• ๋•๋ถ„์— ํŠน์ • ๊ธฐ๋Šฅ(๋ฏน์Šค์ธ)์„ ๊ฐ€์ง„ ๊ฐ์ฒด๋“ค๋งŒ ์ธ์ž๋กœ ๋ฐ›๋Š” ์œ ์—ฐํ•œ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. makeItFly(CanFly flyer) ํ•จ์ˆ˜๊ฐ€ Duck๋ฟ๋งŒ ์•„๋‹ˆ๋ผ with CanFly๋ฅผ ์‚ฌ์šฉํ•œ ์–ด๋–ค ๊ฐ์ฒด(Bird, Airplane ๋“ฑ)๋ผ๋„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ .

Q) ๊ธฐ์กด์— c#์„ ์จ์™”๋˜ ์ž…์žฅ์—์„œ ์ƒ๊ฐ์„ ํ•ด๋ณด๋ฉด, interface์™€ ๊ฐ™์ด ์ƒ์† ํ›„ ๊ตฌํ˜„(implenment)์€ ์•„๋‹Œ ๊ฒƒ ๊ฐ™๊ณ , abstract์™€ ๋น„์Šทํ•œ ๋А๋‚Œ์ธ๋ฐ, ๊ทธ๋Ÿฌ๋ฉด abstract์—์„œ virtual๋กœ ์ƒ์† ๋ฐ›์€ ๋ฉ”์„œ๋“œ๋ฅผ override ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์žฌ์ •์˜ ํ›„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ ๊ฑธ๊นŒ? ๊ทธ๋ฆฌ๊ณ  mixin ์€ ๋ฉ”์„œ๋“œ๋งŒ ๊ธฐ๋Šฅ์œผ๋กœ ์žฅ์ฐฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑธ๊นŒ?

C# ๊ฐœ๋ฐœ์ž ์ž…์žฅ์—์„œ ์ •๋ง ์ข‹์€ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. C#์˜ interface, abstract class, virtual/override ๊ฐœ๋…๊ณผ Dart์˜ mixin์„ ๋น„๊ตํ•˜๋ฉด ๊ทธ ์ฐจ์ด์ ์„ ๋ช…ํ™•ํžˆ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๊ฐ€์ง€ ์งˆ๋ฌธ์— ๋Œ€ํ•ด ๋‚˜๋ˆ ์„œ ๋‹ต๋ณ€ํ•ด ๋“œ๋ฆด๊ฒŒ์š”.


โšก 1. Mixin ๋ฉ”์„œ๋“œ ์žฌ์ •์˜(Override)์™€ ๋™์ž‘ ๋ฐฉ์‹

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋ง์”€๋“œ๋ฆฌ๋ฉด, ๋„ค, ๋ฏน์Šค์ธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜(override)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ C#์˜ abstract class์™€ virtual/override ๋™์ž‘ ๋ฐฉ์‹๊ณผ๋Š” ๊ทผ๋ณธ์ ์ธ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

C#์˜ ๊ฐœ๋…๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ฏน์Šค์ธ์„ ์ดํ•ดํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋น„์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • interface (C#): **โ€œ์„ค๊ณ„๋„โ€**์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๊ธฐ๋Šฅ๋“ค์ด ์žˆ์–ด์•ผ ํ•˜๋Š”์ง€ โ€˜์•ฝ์†โ€™๋งŒ ํ•˜๊ณ , ์‹ค์ œ ๊ตฌํ˜„์€ ํด๋ž˜์Šค์—์„œ ๋ชจ๋‘ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • abstract class (C#): **โ€œ๋ฐ˜์ฏค ์ง€์–ด์ง„ ์ง‘โ€**๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ๊ธฐ๋Šฅ(virtual ๋˜๋Š” ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ)์€ ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ๊ณ , ์ผ๋ถ€(abstract ๋ฉ”์„œ๋“œ)๋Š” ๋น„์–ด ์žˆ์–ด์„œ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ์™„์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • mixin (Dart): **โ€œ์กฐ๋ฆฝ์‹ ๋ถ€ํ’ˆโ€ ๋˜๋Š” โ€œํ”Œ๋Ÿฌ๊ทธ์ธโ€**์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ์™„์„ฑ๋œ ๊ธฐ๋Šฅ ๋ฉ์–ด๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€ ๋‚ด ํด๋ž˜์Šค์— ๊ทธ๋Œ€๋กœ โ€˜์žฅ์ฐฉโ€™ํ•˜๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.

๋™์ž‘ ๋ฐฉ์‹์˜ ์ฐจ์ด: ์ƒ์† ์ฒด์ธ vs ์šฐ์„ ์ˆœ์œ„

C#์˜ override๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค(base)์˜ virtual ๋ฉ”์„œ๋“œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•˜๋Š”, ๋ช…ํ™•ํ•œ ์ƒ์† ๊ณ„์ธต ๊ตฌ์กฐ ์•ˆ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, ๋ฏน์Šค์ธ์€ **โ€œ์šฐ์„ ์ˆœ์œ„โ€**์— ๋”ฐ๋ผ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํด๋ž˜์Šค ์ž์ฒด์— ๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ •ํ•ด์ง„ ๊ทœ์น™์— ๋”ฐ๋ผ ์–ด๋–ค ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ทœ์น™: class ์„ ์–ธ๋ถ€์˜ ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ ์ˆœ์„œ๋กœ ์ ์šฉ๋œ๋‹ค.

class MyRobot extends Machine with Walker, Runner { ... }

๋งŒ์•ฝ Walker์™€ Runner ๋ฏน์Šค์ธ ๋ชจ๋‘์— move()๋ผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, MyRobot ์ธ์Šคํ„ด์Šค์—์„œ move()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— with๋กœ ์ถ”๊ฐ€๋œ Runner์˜ move()๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ MyRobot ํด๋ž˜์Šค ์ž์ฒด์—์„œ move() ๋ฉ”์„œ๋“œ๋ฅผ overrideํ•˜๋ฉด, MyRobot์˜ move()๊ฐ€ ์ตœ์šฐ์„  ์ˆœ์œ„๋ฅผ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ์˜ˆ์‹œ

mixin Walker {
  void move() {
    print("๋‘ ๋ฐœ๋กœ ๊ฑท์Šต๋‹ˆ๋‹ค.");
  }
}

mixin Runner {
  void move() {
    print("๋น ๋ฅด๊ฒŒ ๋‹ฌ๋ฆฝ๋‹ˆ๋‹ค!"); // Walker์˜ move()์™€ ์ด๋ฆ„์ด ๊ฐ™์Œ
  }
}

// 1. Runner์˜ move()๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง
class Robot with Walker, Runner {}

// 2. ํด๋ž˜์Šค ์ž์ฒด์˜ move()๊ฐ€ ์ตœ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง
class AdvancedRobot with Walker, Runner {
  @override
  void move() {
    print("๋ถ€์Šคํ„ฐ๋ฅผ ์ผœ๊ณ  ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค!");
    // super.move(); // ํ˜ธ์ถœ ์‹œ ๋ฐ”๋กœ ์œ„ ์šฐ์„ ์ˆœ์œ„์ธ Runner์˜ move()๊ฐ€ ์‹คํ–‰๋จ
  }
}

void main() {
  var robot = Robot();
  robot.move(); // ์ถœ๋ ฅ: ๋น ๋ฅด๊ฒŒ ๋‹ฌ๋ฆฝ๋‹ˆ๋‹ค!

  var advancedRobot = AdvancedRobot();
  advancedRobot.move(); // ์ถœ๋ ฅ: ๋ถ€์Šคํ„ฐ๋ฅผ ์ผœ๊ณ  ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค!
}

์ •๋ฆฌ: C#์˜ override๊ฐ€ ๋ถ€๋ชจ-์ž์‹ ๊ฐ„์˜ ์ˆ˜์ง์  ์žฌ์ •์˜๋ผ๋ฉด, Dart ๋ฏน์Šค์ธ์˜ ์žฌ์ •์˜๋Š” ํด๋ž˜์Šค ์ž์ฒด์˜ ๊ตฌํ˜„์ด ๋ฏน์Šค์ธ์˜ ๊ตฌํ˜„์„ ๋ฎ์–ด์“ฐ๋Š”(์šฐ์„ ํ•˜๋Š”) ๋ฐฉ์‹์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. super ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ”๋กœ ๋‹ค์Œ ์šฐ์„ ์ˆœ์œ„์˜ ๋ฏน์Šค์ธ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.


โšก 2. Mixin์ด ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋ฉค๋ฒ„

์•„๋‹ˆ์š”, ๋ฏน์Šค์ธ์€ ๋ฉ”์„œ๋“œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ณ€์ˆ˜(ํ”„๋กœํผํ‹ฐ), Getter/Setter ๋“ฑ๋„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ **โ€˜์ฝ”๋“œ ๋ฉ์–ด๋ฆฌโ€™**์ด๋ฏ€๋กœ, ์ƒํƒœ(state)๋ฅผ ์ €์žฅํ•˜๋Š” ๋ณ€์ˆ˜์™€ ๊ทธ ์ƒํƒœ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ํ–‰์œ„(method)๋ฅผ ๋ชจ๋‘ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์˜ˆ์‹œ

mixin BatteryManager {
  // 1. ๋ณ€์ˆ˜ (ํ”„๋กœํผํ‹ฐ)
  double _batteryLevel = 100.0;

  // 2. Getter
  double get batteryStatus => _batteryLevel;

  // 3. ๋ฉ”์„œ๋“œ
  void usePower(double amount) {
    _batteryLevel -= amount;
    if (_batteryLevel < 0) {
      _batteryLevel = 0;
    }
    print("์ „๋ ฅ ์‚ฌ์šฉ! ํ˜„์žฌ ๋ฐฐํ„ฐ๋ฆฌ: ${_batteryLevel.toStringAsFixed(1)}%");
  }

  void charge() {
    _batteryLevel = 100.0;
    print("์ถฉ์ „ ์™„๋ฃŒ!");
  }
}

class Drone with BatteryManager {
  void fly() {
    print("๋“œ๋ก  ๋น„ํ–‰ ์‹œ์ž‘...");
    usePower(15.5); // ๋ฏน์Šค์ธ์˜ ๋ฉ”์„œ๋“œ์™€ ๋ณ€์ˆ˜๋ฅผ ๋‚ด ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ
  }
}

void main() {
  var myDrone = Drone();
  myDrone.fly(); // ์ถœ๋ ฅ: ๋“œ๋ก  ๋น„ํ–‰ ์‹œ์ž‘... -> ์ „๋ ฅ ์‚ฌ์šฉ! ํ˜„์žฌ ๋ฐฐํ„ฐ๋ฆฌ: 84.5%
  
  // ๋ฏน์Šค์ธ์˜ Getter์—๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ
  print("๋“œ๋ก  ๋ฐฐํ„ฐ๋ฆฌ ์ƒํƒœ: ${myDrone.batteryStatus}%"); // ์ถœ๋ ฅ: ๋“œ๋ก  ๋ฐฐํ„ฐ๋ฆฌ ์ƒํƒœ: 84.5%
}

์ด์ฒ˜๋Ÿผ BatteryManager ๋ฏน์Šค์ธ์€ ๋ฐฐํ„ฐ๋ฆฌ ์ž”๋Ÿ‰์ด๋ผ๋Š” ์ƒํƒœ(_batteryLevel)์™€ ๊ด€๋ จ ๋™์ž‘(usePower, charge)์„ ๋ชจ๋‘ ํฌํ•จํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, Drone ํด๋ž˜์Šค๋Š” ์ด ๊ธฐ๋Šฅ๋“ค์„ ๊ทธ๋Œ€๋กœ โ€˜์žฅ์ฐฉโ€™ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿค” ์งˆ๋ฌธ: ์™œ Mixin์ด ํ•„์š”ํ•œ๊ฐ€?

์งˆ๋ฌธ: ์™œ ์ด๋Ÿฐ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฑธ๊นŒ? ์–ด์ฐจํ”ผ ์ƒ์†์„ ๋ฐ›์•„๋„ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ์žˆ๋Š” ๊ธฐ๋Šฅ๋“ค์„ ๊ฐ€์ง€๊ณ  ์™€์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋ง์ด์ง€?

์ •๋ง ์ข‹์€ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ ์งˆ๋ฌธ์ด์•ผ๋ง๋กœ ๋ฏน์Šค์ธ(Mixin)์˜ ์กด์žฌ ์ด์œ ๋ฅผ ๊ด€ํ†ตํ•˜๋Š” ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

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


โš ๏ธ ์ƒ์†๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•œ ์ด์œ : โ€œ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œโ€

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

๊ฐ„๋‹จํ•œ ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • Character ๋ผ๋Š” ์ตœ์ƒ์œ„ ๋ถ€๋ชจ ํด๋ž˜์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Knight ์™€ Magician ์€ Character ๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.
  • Paladin ์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ์บ๋ฆญํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ํŒ”๋ผ๋”˜์€ ๊ธฐ์‚ฌ์˜ ๋Šฅ๋ ฅ(๊ฒ€์ˆ )๊ณผ ๋งˆ๋ฒ•์‚ฌ์˜ ๋Šฅ๋ ฅ(์น˜์œ  ๋งˆ๋ฒ•)์„ ๋ชจ๋‘ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์ƒ์†๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

  1. class Paladin extends Knight { ... }
    • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ์‚ฌ์˜ ๋Šฅ๋ ฅ์€ ๋ฌผ๋ ค๋ฐ›์ง€๋งŒ, ๋งˆ๋ฒ•์‚ฌ์˜ ๋Šฅ๋ ฅ์€ ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ Magician ํด๋ž˜์Šค์— ์žˆ๋˜ ์น˜์œ  ๋งˆ๋ฒ• ์ฝ”๋“œ๋ฅผ Paladin ํด๋ž˜์Šค์— ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. class Paladin extends Magician { ... }
    • ๋ฐ˜๋Œ€๋กœ ํ•˜๋ฉด ๊ฒ€์ˆ  ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๋“  ์ฝ”๋“œ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ์น˜์œ  ๋งˆ๋ฒ•์˜ ์„ฑ๋Šฅ์„ ์ˆ˜์ •ํ•˜๋ ค๋ฉด Magician๊ณผ Paladin ๋‘ ํด๋ž˜์Šค๋ฅผ ๋ชจ๋‘ ๊ณ ์ณ์•ผ ํ•˜๋Š” ๋”์ฐํ•œ ์ƒํ™ฉ์ด ์ƒ๊ธฐ์ฃ .

์ด์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ๋ถ€๋ชจ์˜ ํŠน์ง•์„ ๋™์‹œ์— ๋ฌผ๋ ค๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ ๋‹จ์ผ ์ƒ์†์˜ ํ•œ๊ณ„๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ **โ€œ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ(Diamond Problem)โ€**๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

C#์—์„œ๋Š” ์ด ๋ฌธ์ œ๋ฅผ interface๋กœ ์ผ๋ถ€ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. IHasSwordSkills, IHasHealingMagic ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด Paladin์ด ๋‘˜ ๋‹ค ๊ตฌํ˜„(implements)ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์ฃ . ํ•˜์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค๋Š” โ€˜๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€โ€™๋งŒ ์ •์˜ํ•  ๋ฟ, โ€˜์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€โ€™์— ๋Œ€ํ•œ ์‹ค์ œ ์ฝ”๋“œ(๊ตฌํ˜„)๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ตญ ์ฝ”๋“œ ์ค‘๋ณต ๋ฌธ์ œ๋Š” ์—ฌ์ „ํžˆ ๋‚จ์Šต๋‹ˆ๋‹ค.


โœ… ๋ฏน์Šค์ธ์˜ ํ•ด๊ฒฐ์ฑ…: ๊ธฐ๋Šฅ์˜ ์กฐํ•ฉ(Composition)

๋ฏน์Šค์ธ์€ ์ด ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ•ต์‹ฌ์ ์ธ ๋Šฅ๋ ฅ๋“ค์„ โ€˜๋ถ€ํ’ˆโ€™์ฒ˜๋Ÿผ ๋งŒ๋“ค์–ด๋‘๊ณ , ํ•„์š”ํ•œ ํด๋ž˜์Šค์— โ€˜์žฅ์ฐฉโ€™๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

1. ๋Šฅ๋ ฅ(Mixin)์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

mixin SwordSkills {
  void attackWithSword() => print("๊ฒ€์œผ๋กœ ๊ณต๊ฒฉ!");
}

mixin HealingMagic {
  void heal() => print("์น˜์œ  ๋งˆ๋ฒ• ์‹œ์ „!");
}

2. ํ•„์š”ํ•œ ํด๋ž˜์Šค์— with๋กœ ์žฅ์ฐฉํ•ฉ๋‹ˆ๋‹ค.

class Character {}

// ๊ธฐ์‚ฌ๋Š” ๊ฒ€์ˆ  ๋Šฅ๋ ฅ์„ ์žฅ์ฐฉ
class Knight extends Character with SwordSkills {}

// ๋งˆ๋ฒ•์‚ฌ๋Š” ์น˜์œ  ๋งˆ๋ฒ• ๋Šฅ๋ ฅ์„ ์žฅ์ฐฉ
class Magician extends Character with HealingMagic {}

// ํŒ”๋ผ๋”˜์€ ๊ฒ€์ˆ ๊ณผ ์น˜์œ  ๋งˆ๋ฒ• ๋Šฅ๋ ฅ์„ ๋ชจ๋‘ ์žฅ์ฐฉ
class Paladin extends Character with SwordSkills, HealingMagic {}

์ด์ œ Paladin ํด๋ž˜์Šค๋Š” ์ฝ”๋“œ๋ฅผ ๋‹จ ํ•œ ์ค„๋„ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  attackWithSword()์™€ heal() ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์น˜์œ  ๋งˆ๋ฒ•์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด HealingMagic ๋ฏน์Šค์ธ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ค‘๋ณต์ด ์‚ฌ๋ผ์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๋งค์šฐ ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.


๐Ÿ“‹ ์ƒ์†(extends) vs ๋ฏน์Šค์ธ(with)์˜ ์—ญํ• 

๊ตฌ๋ถ„ extends (์ƒ์†) with (๋ฏน์Šค์ธ)
๊ด€๊ณ„ โ€œis aโ€ (A๋Š” B์ด๋‹ค) โ€œcan doโ€ (A๋Š” B๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค)
๋ชฉ์  ํด๋ž˜์Šค์˜ ํ•ต์‹ฌ ์ •์ฒด์„ฑ์„ ์ •์˜ (์ˆ˜์ง์  ๊ด€๊ณ„) ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— ๊ฑธ์ณ ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉ (์ˆ˜ํ‰์  ์ถ”๊ฐ€)
์˜ˆ์‹œ Paladin is a Character. Paladin can do SwordSkills and HealingMagic.

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ

โœ… ์˜ค๋Š˜ ๋ฐฐ์šด ๊ฒƒ

  • extends vs with: ์ƒ์†์€ โ€œis aโ€ ๊ด€๊ณ„, ๋ฏน์Šค์ธ์€ โ€œcan doโ€ ๊ด€๊ณ„
  • Mixin ์ •์˜: mixin ํ‚ค์›Œ๋“œ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ ๋ฉ์–ด๋ฆฌ ์ƒ์„ฑ
  • ํƒ€์ž… ์บ์ŠคํŒ…: with๋กœ ์ถ”๊ฐ€ํ•œ ๋ฏน์Šค์ธ์œผ๋กœ ํƒ€์ž… ์บ์ŠคํŒ… ๊ฐ€๋Šฅ
  • ๋ฉ”์„œ๋“œ ์žฌ์ •์˜: ๋ฏน์Šค์ธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํด๋ž˜์Šค์—์„œ ์˜ค๋ฒ„๋ผ์ด๋“œ ๊ฐ€๋Šฅ
  • ๋‹ค์–‘ํ•œ ๋ฉค๋ฒ„: ๋ฏน์Šค์ธ์€ ๋ฉ”์„œ๋“œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ณ€์ˆ˜, getter/setter๋„ ํฌํ•จ ๊ฐ€๋Šฅ
  • ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ ํ•ด๊ฒฐ: ๋‹จ์ผ ์ƒ์†์˜ ํ•œ๊ณ„๋ฅผ ๋ฏน์Šค์ธ์œผ๋กœ ๊ทน๋ณต

๐Ÿš€ ๋‹ค์Œ ๊ณ„ํš

  • Flutter์—์„œ Mixin ํ™œ์šฉ: TickerProviderStateMixin ๋“ฑ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€ ํ•™์Šต
  • Advanced Mixin Pattern: ๋ณตํ•ฉ ๋ฏน์Šค์ธ๊ณผ ์ƒ์† ์ฒด์ธ ์กฐํ•ฉ ์—ฐ๊ตฌ
  • Performance: ๋ฏน์Šค์ธ ์‚ฌ์šฉ ์‹œ ์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ ํ•™์Šต

๐Ÿ’ก ํ•ต์‹ฌ: ๋ฏน์Šค์ธ์€ ์ƒ์†์„ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ƒ์†์˜ ์ˆ˜์ง์  ๊ตฌ์กฐ๋ฅผ ๋ณด์™„ํ•˜๋Š” ์ˆ˜ํ‰์  ๊ธฐ๋Šฅ ์กฐํ•ฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์—ฌ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋”์šฑ ํ’๋ถ€ํ•˜๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ•ต์‹ฌ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค! ๐Ÿงฉ

ํƒœ๊ทธ: , , ,

์นดํ…Œ๊ณ ๋ฆฌ: ,

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ