๐ฆ Perl์ Moose: ํ๋์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ ์ธ๊ณ ๐

์๋ , ์น๊ตฌ๋ค! ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ก ์ฌ๋ฌ๋ถ๊ณผ ํจ๊ปํ ๊ฑฐ์ผ. ๋ฐ๋ก Perl์ Moose๋ผ๋ ๋๋ผ์ด ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์์คํ ์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ ๊ฑฐ๊ฑฐ๋ . ๐ ์ค๋น๋์ด? ๊ทธ๋ผ ์์ํด๋ณผ๊น?
๋จผ์ , Perl์ด ๋ญ์ง ๋ชจ๋ฅด๋ ์น๊ตฌ๋ค์ ์ํด ๊ฐ๋จํ ์ค๋ช ํด์ค๊ฒ. Perl์ ์ค์ฉ์ ์ธ ์ถ์ถ ๋ฐ ๋ณด๊ณ ์ธ์ด(Practical Extraction and Report Language)์ ์ฝ์๋ก, 1987๋ ์ ๋๋ฆฌ ์์ด ๋ง๋ ๊ณ ๊ธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ผ. ํ ์คํธ ์ฒ๋ฆฌ์ ํนํ๋์ด ์๊ณ , ์ ์ฐ์ฑ์ด ๋ฐ์ด๋์ "์ค์์ค ๊ตฐ์ฉ ์นผ"์ด๋ผ๊ณ ๋ ๋ถ๋ฆฐ๋. ๊ทผ๋ฐ ์ค๋ ์ฐ๋ฆฌ๊ฐ ์ง์ค์ ์ผ๋ก ๋ณผ ๊ฑด Perl์ Moose๋ผ๋ ํน๋ณํ ๋ ์์ด์ผ.
Moose๋ Perl์ ํ๋์ ์ด๊ณ ๊ฐ๋ ฅํ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐํด์ฃผ๋ ํ์ฅ ๋ชจ๋์ด์ผ. ๋ง์น Perl์ ์คํ ๋ก์ด๋๋ฅผ ์ฃผ์ฌํ ๊ฒ ๊ฐ๋ค๊ณ ๋ ํ ๊น? ๐ Moose๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๊ฐ์ฒด ์งํฅ ์ค๊ณ๋ฅผ ํจ์ฌ ์ฝ๊ณ ๊น๋ํ๊ฒ ๊ตฌํํ ์ ์์ด. ๊ทธ๋ผ ์ด์ ๋ถํฐ Moose์ ์ธ๊ณ๋ก ๊น์ด ๋ค์ด๊ฐ ๋ณผ ํ ๋ฐ, ์ค๋น๋์ง?
๐ ์ฌ๋ฅ๋ท ํ: ํ๋ก๊ทธ๋๋ฐ ์ค๋ ฅ์ ํฅ์์ํค๊ณ ์ถ๋ค๋ฉด ์ฌ๋ฅ๋ท(https://www.jaenung.net)์์ Perl ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์๋ณด๋ ๊ฒ์ ์ด๋จ๊น? ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ ๊น์ด ์๋ ์ดํด๋ ๋ค์ํ ํ๋ก์ ํธ์์ ํฐ ๋์์ด ๋ ๊ฑฐ์ผ!
๐ฆ Moose๋ ๋ฌด์์ธ๊ฐ? ๐ค
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Moose์ ๋ํด ์์๋ณผ ์ฐจ๋ก์ผ. Moose๋ผ๋ ์ด๋ฆ์ด ์ ๋ถ์๋์ง ๊ถ๊ธํ์ง ์์? Moose๋ ์์ด๋ก 'ํฐ ์ฌ์ด'์ ์๋ฏธํด. ์ ํํ ์ฌ์ด์ด๋๊ณ ? ๊ธ์, ์๋ง๋ Moose๊ฐ Perl์ ์ธ๊ณ์์ ํฌ๊ณ ๊ฐ๋ ฅํ ์กด์ฌ๋ผ๋ ๊ฑธ ํํํ๊ณ ์ถ์๋ ๋ด. ๐ฆ
Moose๋ Perl 5์ ํ๋์ ์ด๊ณ ์ ์ธ์ ์ธ ๊ฐ์ฒด ์์คํ ์ ์ ๊ณตํ๋ ํฌ์คํธ๋ชจ๋ ๊ฐ์ฒด ์์คํ ์ด์ผ. ๋ญ ๋ง์ธ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ? ๊ฑฑ์ ๋ง, ์ฒ์ฒํ ์ค๋ช ํด์ค๊ฒ!
์ผ๋จ Moose๋ ๋ค์๊ณผ ๊ฐ์ ํน์ง์ ๊ฐ์ง๊ณ ์์ด:
- ํด๋์ค์ ์ญํ (role) ์ ์ธ์ ์ํ ์ ์ธ์ ๊ตฌ๋ฌธ
- ํ์ ์ ์ฝ ์กฐ๊ฑด๊ณผ ๊ฐ๋ ฅํ ํ์ ์์คํ
- ๋ฉํํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฅ
- ์์๊ณผ ๋ค์ค ์์ ์ง์
- ์๋ ์์ฑ์์ ์ ๊ทผ์ ๋ฉ์๋
- ์์ฑ ์์
์ด๋ฐ ํน์ง๋ค ๋๋ถ์ Moose๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๊ฐ์ฒด ์งํฅ ์ค๊ณ๋ฅผ ํจ์ฌ ์ฝ๊ณ ๊น๋ํ๊ฒ ๊ตฌํํ ์ ์์ด. ๋ง์น ๋ ๊ณ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ฏ์ด ๊ฐ์ฒด ์์คํ ์ ๋ง๋ค ์ ์๋ค๊ณ ์๊ฐํ๋ฉด ๋ผ.
๐ฏ ๊ฟํ: Moose๋ฅผ ์ฒ์ ์ ํ๋ฉด ์ข ๋ณต์กํด ๋ณด์ผ ์ ์์ด. ํ์ง๋ง ๊ฑฑ์ ๋ง! ์กฐ๊ธ๋ง ์ต์ํด์ง๋ฉด ์ ๋ง ํธ๋ฆฌํ๊ณ ๊ฐ๋ ฅํ ๋๊ตฌ๋ผ๋ ๊ฑธ ๋๋ ์ ์์ ๊ฑฐ์ผ. ๋ง์น ์ฒ์ ์์ ๊ฑฐ ํ๋ ๋ฒ์ ๋ฐฐ์ธ ๋์ฒ๋ผ, ์ฒ์์ ์ด๋ ต์ง๋ง ํ๋ฒ ์ต์ํด์ง๋ฉด ์ ๋ง ์ฆ๊ฑฐ์์ง ๊ฑฐ์ผ!
Moose๋ Perl ์ปค๋ฎค๋ํฐ์์ ์์ฒญ๋ ์ธ๊ธฐ๋ฅผ ์ป๊ณ ์์ด. ์ ๊ทธ๋ด๊น? ๋ฐ๋ก Moose๊ฐ ์ ๊ณตํ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ค ๋๋ฌธ์ด์ง. ์๋ฅผ ๋ค์ด, ํ์ ์ฒดํน, ์๋ ์์ฑ์, ๋ฉํํ๋ก๊ทธ๋๋ฐ ๋ฑ์ ๊ธฐ๋ฅ์ ๊ฐ๋ฐ์๋ค์ ์ถ์ ํจ์ฌ ํธํ๊ฒ ๋ง๋ค์ด์ฃผ๊ฑฐ๋ .
Moose๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ด ํฌ๊ฒ ํฅ์๋ผ. ์ด๊ฑด ํนํ ํฐ ํ๋ก์ ํธ์์ ์ ๋ง ์ค์ํ ์ฅ์ ์ด์ผ. ์ฝ๋๊ฐ ๊น๋ํ๊ณ ๊ตฌ์กฐํ๋์ด ์์ผ๋ฉด, ๋์ค์ ์์ ํ๊ฑฐ๋ ํ์ฅํ๊ธฐ๊ฐ ํจ์ฌ ์ฌ์์ง๊ฑฐ๋ .
์์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด Moose์ ์ฃผ์ ํน์ง๋ค์ ํ๋์ ๋ณผ ์ ์์ง? ์ด ํน์ง๋ค์ด ๋ฐ๋ก Moose๋ฅผ ๊ฐ๋ ฅํ๊ณ ์ ์ฉํ ๋๊ตฌ๋ก ๋ง๋๋ ์์๋ค์ด์ผ. ์ด์ ์ด ํน์ง๋ค์ ๋ํด ํ๋์ฉ ์์ธํ ์์๋ณผ ๊ฑฐ์ผ. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐๏ธ Moose๋ก ํด๋์ค ๋ง๋ค๊ธฐ
์, ์ด์ Moose๋ฅผ ์ฌ์ฉํด์ ์ค์ ๋ก ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ. ๊ฑฑ์ ๋ง, ์ด๋ ต์ง ์์! ๋ง์น ๋ ๊ณ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ ๊ฒ์ฒ๋ผ ์ฝ๊ณ ์ฌ๋ฏธ์์ ๊ฑฐ์ผ. ๐
๋จผ์ , Moose๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ Perl ์คํฌ๋ฆฝํธ์ ๋งจ ์์ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํด:
use Moose;
์ด๋ ๊ฒ ํ๋ฉด Moose์ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ผ. ๊ฐ๋จํ์ง?
์ด์ ์ค์ ๋ก ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ๊น? ์๋ฅผ ๋ค์ด, '๋๋ฌผ'์ด๋ผ๋ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด์.
package Animal;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'age' => (is => 'rw', isa => 'Int');
sub make_sound {
my $self = shift;
print $self->name . " makes a sound.\n";
}
1;
์ฐ์, ์ด๊ฒ ๋ญ๊น? ํ๋์ฉ ์ค๋ช ํด์ค๊ฒ:
package Animal;
: ์ด๊ฑด ์ฐ๋ฆฌ๊ฐ ๋ง๋ค ํด๋์ค์ ์ด๋ฆ์ด์ผ.use Moose;
: Moose๋ฅผ ์ฌ์ฉํ๊ฒ ๋ค๊ณ ์ ์ธํ๋ ๊ฑฐ์ผ.has 'name' => (is => 'rw', isa => 'Str');
: ์ด๊ฑด 'name'์ด๋ผ๋ ์์ฑ์ ๋ง๋๋ ๊ฑฐ์ผ. 'rw'๋ ์ฝ๊ธฐ/์ฐ๊ธฐ๊ฐ ๊ฐ๋ฅํ๋ค๋ ๋ป์ด๊ณ , 'Str'์ ๋ฌธ์์ด ํ์ ์ด๋ผ๋ ๋ป์ด์ผ.has 'age' => (is => 'rw', isa => 'Int');
: ์ด๊ฑด 'age'๋ผ๋ ์์ฑ์ ๋ง๋๋ ๊ฑฐ์ผ. 'Int'๋ ์ ์ ํ์ ์ด๋ผ๋ ๋ป์ด์ง.sub make_sound { ... }
: ์ด๊ฑด ๋ฉ์๋๋ฅผ ์ ์ํ๋ ๋ถ๋ถ์ด์ผ. ๋๋ฌผ์ด ์๋ฆฌ๋ฅผ ๋ด๋ ๊ธฐ๋ฅ์ ๊ตฌํํ์ด.1;
: ์ด๊ฑด Perl ๋ชจ๋์ ๋์ ๋ํ๋ด๋ ๊ด๋ก์ ์ธ ํํ์ด์ผ.
์ด๋ ๊ฒ ํ๋ฉด 'Animal' ํด๋์ค๊ฐ ์์ฑ๋ ๊ฑฐ์ผ! ์ ๋ง ๊ฐ๋จํ์ง? Moose๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ ๊ฒ ์ฝ๊ฒ ํด๋์ค๋ฅผ ๋ง๋ค ์ ์์ด.
๐ฑ ์ด๋ณด์ ํ: ํด๋์ค๋ฅผ ๋ง๋ค ๋๋ ๊ทธ ํด๋์ค๊ฐ ์ด๋ค ์์ฑ(๋ฐ์ดํฐ)์ ๊ฐ์ ธ์ผ ํ๋์ง, ์ด๋ค ํ๋(๋ฉ์๋)์ ํ ์ ์์ด์ผ ํ๋์ง ๋ฏธ๋ฆฌ ์๊ฐํด๋ณด๋ ๊ฒ ์ข์. ๋ง์น ์บ๋ฆญํฐ๋ฅผ ๋ง๋๋ ๊ฒ์์ฒ๋ผ ์๊ฐํ๋ฉด ์ฌ๋ฏธ์์ ๊ฑฐ์ผ!
์ด์ ์ด ํด๋์ค๋ฅผ ์ฌ์ฉํด๋ณผ๊น? ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ด:
my $dog = Animal->new(name => 'Buddy', age => 5);
$dog->make_sound(); # ์ถ๋ ฅ: Buddy makes a sound.
์! ์ฐ๋ฆฌ๊ฐ ๋ง๋ ํด๋์ค๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋ฉ์๋๋ฅผ ํธ์ถํ์ด. ์ ๋ง ๋ฉ์ง์ง ์์?
Moose๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ํ ์ ์์ด. ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ์์ฑ์ ์ ์ํ๊ณ , ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๊ฒ ์ ๋ง ์ฝ์ง? ์ด๊ฒ ๋ฐ๋ก Moose์ ๋งค๋ ฅ์ด์ผ!
์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์ฐ๋ฆฌ๊ฐ ๋ง๋ Animal ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ํ๋์ ๋ณผ ์ ์์ด. ํด๋์ค๋ ์์ฑ(๋ฐ์ดํฐ)๊ณผ ๋ฉ์๋(ํ๋)๋ก ๊ตฌ์ฑ๋์ด ์์ง. ์ด๋ ๊ฒ ๊ตฌ์กฐํ๋ ์ค๊ณ๋ ์ฝ๋๋ฅผ ์ดํดํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐ ํฐ ๋์์ด ๋ผ.
Moose๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฐ ํด๋์ค ์ค๊ณ๋ฅผ ์ ๋ง ์ฝ๊ณ ๋ช ํํ๊ฒ ํ ์ ์์ด. ๊ทธ๋์ ๋ง์ Perl ๊ฐ๋ฐ์๋ค์ด Moose๋ฅผ ์ฌ๋ํ๋ค๊ณ ํ ์ ์์ง!
๐ ๋์ ๊ณผ์ : ๋ฐฉ๊ธ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก 'Car' ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ๋? 'brand', 'model', 'year' ์์ฑ์ ๊ฐ์ง๊ณ , 'start_engine'์ด๋ผ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด์. ํ ์ ์์ ๊ฑฐ์ผ!
์, ์ด์ Moose๋ก ํด๋์ค๋ฅผ ๋ง๋๋ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ด. ํ์ง๋ง ์ด๊ฒ ๋์ด ์๋์ผ. Moose๋ ์ด๊ฒ๋ณด๋ค ํจ์ฌ ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํด. ๋ค์ ์น์ ์์๋ Moose์ ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐งฌ Moose์ ์์๊ณผ ๋ค์ค ์์
์, ์ด์ Moose์ ๋ ๋ค๋ฅธ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ธ ์์์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ์์์ด ๋ญ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ? ๊ฑฑ์ ๋ง, ์ฝ๊ฒ ์ค๋ช ํด์ค๊ฒ! ๐
์์์ ๊ธฐ์กด์ ํด๋์ค๋ฅผ ๋ฐํ์ผ๋ก ์๋ก์ด ํด๋์ค๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ด์ผ. ๋ง์น ๋ถ๋ชจ๋ก๋ถํฐ ์ ์ ์๋ฅผ ๋ฌผ๋ ค๋ฐ๋ ๊ฒ์ฒ๋ผ, ๊ธฐ์กด ํด๋์ค์ ํน์ฑ์ ๋ฌผ๋ ค๋ฐ์ ์๋ก์ด ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฑฐ์ง. ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉํ ์ ์๊ณ , ๊ตฌ์กฐ๋ฅผ ๋ ์ฒด๊ณ์ ์ผ๋ก ๋ง๋ค ์ ์์ด.
Moose์์๋ ์์์ ์์ฃผ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ด. ์๋ฅผ ๋ค์ด, ์ฐ๋ฆฌ๊ฐ ์์ ๋ง๋ 'Animal' ํด๋์ค๋ฅผ ์์๋ฐ์ 'Dog' ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ๊น?
package Dog;
use Moose;
extends 'Animal';
has 'breed' => (is => 'rw', isa => 'Str');
override 'make_sound' => sub {
my $self = shift;
print $self->name . " barks: Woof! Woof!\n";
};
1;
์ฐ์, ์ด๊ฒ ๋ญ๊น? ํ๋์ฉ ์ค๋ช ํด์ค๊ฒ:
extends 'Animal';
: ์ด ๋ถ๋ถ์ด ๋ฐ๋ก 'Animal' ํด๋์ค๋ฅผ ์์๋ฐ๋๋ค๋ ๋ป์ด์ผ.has 'breed' => (is => 'rw', isa => 'Str');
: 'Dog' ํด๋์ค์๋ง ์๋ ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ์ด.override 'make_sound' => sub { ... };
: ์ด๊ฑด ๋ถ๋ชจ ํด๋์ค์ 'make_sound' ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋(์ฌ์ ์)ํ๋ ๊ฑฐ์ผ.
์ด๋ ๊ฒ ํ๋ฉด 'Dog' ํด๋์ค๋ 'Animal' ํด๋์ค์ ๋ชจ๋ ํน์ฑ์ ๋ฌผ๋ ค๋ฐ์ผ๋ฉด์๋, ์์ ๋ง์ ํน๋ณํ ๊ธฐ๋ฅ์ ๊ฐ์ง ์ ์์ด. ๋ฉ์ง์ง ์์?
๐พ ๊ฐ๋ ์ ๋ฆฌ: ์์์ ํตํด ๋ง๋ค์ด์ง ์๋ก์ด ํด๋์ค๋ฅผ '์์ ํด๋์ค' ๋๋ '์๋ธ ํด๋์ค'๋ผ๊ณ ํด. ์์์ ํด์ค ์๋ ํด๋์ค๋ '๋ถ๋ชจ ํด๋์ค' ๋๋ '์ํผ ํด๋์ค'๋ผ๊ณ ๋ถ๋ฌ. ์ฐ๋ฆฌ ์์ ์์๋ 'Dog'๊ฐ ์์ ํด๋์ค, 'Animal'์ด ๋ถ๋ชจ ํด๋์ค์ธ ๊ฑฐ์ง!
์ด์ ์ด 'Dog' ํด๋์ค๋ฅผ ์ฌ์ฉํด๋ณผ๊น?
my $buddy = Dog->new(name => 'Buddy', age => 5, breed => 'Golden Retriever');
$buddy->make_sound(); # ์ถ๋ ฅ: Buddy barks: Woof! Woof!
์! 'Dog' ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋ฉ์๋๋ฅผ ํธ์ถํ์ด. 'Animal' ํด๋์ค์ ์์ฑ(name, age)๋ ์ฌ์ฉํ ์ ์๊ณ , 'Dog' ํด๋์ค๋ง์ ์์ฑ(breed)๋ ์ฌ์ฉํ ์ ์์ด. ๊ฒ๋ค๊ฐ 'make_sound' ๋ฉ์๋๋ ๊ฐ์ ๋ง๊ฒ ๋ณ๊ฒฝ๋์์ง. ์ ๋ง ๋ฉ์ง์ง ์์?
ํ์ง๋ง Moose์ ์์ ๊ธฐ๋ฅ์ ์ฌ๊ธฐ์ ๋์ด ์๋์ผ. Moose๋ ๋ค์ค ์์๋ ์ง์ํด! ๋ค์ค ์์์ด ๋ญ๋๊ณ ? ํ ํด๋์ค๊ฐ ์ฌ๋ฌ ํด๋์ค๋ฅผ ๋์์ ์์๋ฐ๋ ๊ฑฐ์ผ. ์๋ฅผ ๋ค์ด๋ณผ๊ฒ:
package SuperDog;
use Moose;
extends 'Dog', 'SuperPower';
1;
์ด๋ ๊ฒ ํ๋ฉด 'SuperDog' ํด๋์ค๋ 'Dog'์ 'SuperPower' ๋ ํด๋์ค์ ํน์ฑ์ ๋ชจ๋ ๋ฌผ๋ ค๋ฐ๊ฒ ๋ผ. ๋ง์น ์ํผํ์ด๋ก ๊ฐ๋ฅผ ๋ง๋ ๊ฒ ๊ฐ์ง ์์? ๐
์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด ํด๋์ค ๊ฐ์ ์์ ๊ด๊ณ๋ฅผ ํ๋์ ๋ณผ ์ ์์ด. 'Animal'์ ์ต์์ ํด๋์ค๊ณ , 'Dog'์ 'SuperPower'๋ ๊ฐ๊ฐ 'Animal'์ ์์๋ฐ์์ด. ๊ทธ๋ฆฌ๊ณ 'SuperDog'๋ 'Dog'์ 'SuperPower' ๋ ํด๋์ค๋ฅผ ๋ชจ๋ ์์๋ฐ์์ง. ์ด๋ ๊ฒ ๋ณต์กํ ๊ด๊ณ๋ Moose๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๊ฒ ๊ตฌํํ ์ ์์ด!
ํ์ง๋ง ๋ค์ค ์์์ ์กฐ์ฌํด์ ์ฌ์ฉํด์ผ ํด. ์ฌ๋ฌ ๋ถ๋ชจ ํด๋์ค์์ ๊ฐ์ ์ด๋ฆ์ ๋ฉ์๋๋ ์์ฑ์ด ์๋ค๋ฉด ์ถฉ๋์ด ์ผ์ด๋ ์ ์๊ฑฐ๋ . ์ด๋ฐ ๋ฌธ์ ๋ฅผ '๋ค์ด์๋ชฌ๋ ๋ฌธ์ '๋ผ๊ณ ๋ถ๋ฌ. Moose๋ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ๋ ์ ๊ณตํ์ง๋ง, ๊ฐ๋ฅํ๋ฉด ๋จ์ผ ์์์ ์ฌ์ฉํ๋ ๊ฒ ์ข์.
๐ ๊ณ ๊ธ ํ: ๋ค์ค ์์ ๋์ Moose์ 'Role' ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. Role์ ๋ค์ค ์์์ ์ฅ์ ์ ์ด๋ฆฌ๋ฉด์ ๋จ์ ์ ์ค์ผ ์ ์๋ ๋ฉ์ง ๊ธฐ๋ฅ์ด์ง. ๋์ค์ ๋ ์์ธํ ์์๋ณผ ๊ฑฐ์ผ!
์, ์ด์ Moose์ ์์์ ๋ํด ์์๋ดค์ด. ์์์ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉํ๊ณ ๊ตฌ์กฐํํ๋ ๋ฐ ํฐ ๋์์ด ๋ผ. ํ์ง๋ง ๋๋ฌด ๋ณต์กํ ์์ ๊ตฌ์กฐ๋ ์คํ๋ ค ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ผ๋ ์ฃผ์ํด์ผ ํด.
๋ค์ ์น์ ์์๋ Moose์ ๋ ๋ค๋ฅธ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ธ 'ํ์ ์ ์ฝ ์กฐ๊ฑด'์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐ญ Moose์ ํ์ ์ ์ฝ ์กฐ๊ฑด
์๋ , ์น๊ตฌ๋ค! ์ด๋ฒ์๋ Moose์ ์ ๋ง ๋ฉ์ง ๊ธฐ๋ฅ ์ค ํ๋์ธ 'ํ์ ์ ์ฝ ์กฐ๊ฑด'์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ์ด๊ฒ ๋ญ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ? ๊ฑฑ์ ๋ง, ์ฒ์ฒํ ์ค๋ช ํด์ค๊ฒ! ๐
ํ์ ์ ์ฝ ์กฐ๊ฑด์ ํด๋์ค์ ์์ฑ์ ๋ค์ด๊ฐ ์ ์๋ ๋ฐ์ดํฐ์ ์ข ๋ฅ๋ฅผ ์ ํํ๋ ๊ธฐ๋ฅ์ด์ผ. ์ฝ๊ฒ ๋งํด, ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ง ์์ฑ์ ๋ฃ์ ์ ์๊ฒ ํด์ฃผ๋ ๊ฑฐ์ง. ์ด๋ ๊ฒ ํ๋ฉด ์๋ชป๋ ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ง์ ์ ์์ด์ ํ๋ก๊ทธ๋จ์ ์์ ์ฑ์ด ๋์์ ธ.
์๋ฅผ ๋ค์ด๋ณผ๊น? ์ฐ๋ฆฌ๊ฐ ๋ง๋ 'Dog' ํด๋์ค๋ฅผ ์กฐ๊ธ ์์ ํด๋ณผ๊ฒ:
package Dog;
use Moose;
use Moose::Util::TypeConstraints;
extends 'Animal';
has 'breed' => (is => 'rw', isa => 'Str');
has 'age' => (is => 'rw', isa => 'Int', where => sub { $_ > 0 });
has 'toys' => (is => 'rw', isa => 'ArrayRef[Str]');
enum 'DogSize' => qw(small medium large);
has 'size' => (is => 'rw', isa => 'DogSize');
1;
์ฐ์, ๋ง์ด ๋ฌ๋ผ์ก์ง? ํ๋์ฉ ์ค๋ช ํด์ค๊ฒ:
use Moose::Util::TypeConstraints;
: ์ด๊ฑด ์ถ๊ฐ์ ์ธ ํ์ ์ ์ฝ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํ ๊ฑฐ์ผ.has 'breed' => (is => 'rw', isa => 'Str');
: 'breed'๋ ๋ฌธ์์ด(Str)์ด์ด์ผ ํด.has 'age' => (is => 'rw', isa => 'Int', where => sub { $_ > 0 });
: 'age'๋ ์ ์(Int)์ฌ์ผ ํ๊ณ , 0๋ณด๋ค ์ปค์ผ ํด.has 'toys' => (is => 'rw', isa => 'ArrayRef[Str]');
: 'toys'๋ ๋ฌธ์์ด ๋ฐฐ์ด์ด์ด์ผ ํด.enum 'DogSize' => qw(small medium large);
: 'DogSize'๋ผ๋ ์๋ก์ด ํ์ ์ ๋ง๋ค์์ด. ์ด ํ์ ์ 'small', 'medium', 'large' ์ค ํ๋์ ๊ฐ๋ง ๊ฐ์ง ์ ์์ด.has 'size' => (is => 'rw', isa => 'DogSize');
: 'size'๋ ์ฐ๋ฆฌ๊ฐ ๋ง๋ 'DogSize' ํ์ ์ด์ด์ผ ํด.
์ด๋ ๊ฒ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ๋ฉด, ์ฐ๋ฆฌ๊ฐ ์ํ๋ ํํ์ ๋ฐ์ดํฐ๋ง ์์ฑ์ ๋ค์ด๊ฐ ์ ์์ด. ๋ง์ฝ ์๋ชป๋ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ผ๋ ค๊ณ ํ๋ฉด Moose๊ฐ ์๋ฌ๋ฅผ ๋ฐ์์์ผ์ค. ์ ๋ง ํธ๋ฆฌํ์ง ์์?
๐งช ์คํํด๋ณด๊ธฐ: ๋ค์ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด ์ด๋ป๊ฒ ๋ ๊น? my $dog = Dog->new(name => 'Buddy', age => -5, size => 'huge');
์๋ฌ๊ฐ ๋ ๊ฑฐ์ผ! ์๋ํ๋ฉด ๋์ด๋ 0๋ณด๋ค ์ปค์ผ ํ๊ณ , ํฌ๊ธฐ๋ 'small', 'medium', 'large' ์ค ํ๋์ฌ์ผ ํ๋๊น.
Moose์ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ์ ๋ง ๊ฐ๋ ฅํด. ๊ธฐ๋ณธ ํ์ (Str, Int, ArrayRef ๋ฑ) ์ธ์๋ ๋ณต์กํ ํ์ ์ ๋ง๋ค ์ ์์ด. ์๋ฅผ ๋ค์ด, ์ ๊ท ํํ์์ ์ฌ์ฉํด์ ์ด๋ฉ์ผ ์ฃผ์๋ ์ ํ๋ฒํธ ํ์์ ๊ฒ์ฌํ ์๋ ์์ง:
subtype 'Email',
as 'Str',
where => sub { $_ =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/ },
message => "Invalid email address";
has 'email' => (is => 'rw', isa => 'Email');
์ด๋ ๊ฒ ํ๋ฉด 'email' ์์ฑ์๋ ์ฌ๋ฐ๋ฅธ ํ์์ ์ด๋ฉ์ผ ์ฃผ์๋ง ๋ค์ด๊ฐ ์ ์์ด. ๋ฉ์ง์ง ์์?
์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด 'Dog' ํด๋์ค์ ๊ฐ ์์ฑ์ ์ด๋ค ํ์ ์ ์ฝ ์กฐ๊ฑด์ด ๊ฑธ๋ ค์๋์ง ํ๋์ ๋ณผ ์ ์์ด. ์ด๋ ๊ฒ ๋ช ํํ ๊ตฌ์กฐ๋ ์ฝ๋๋ฅผ ์ดํดํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐ ํฐ ๋์์ด ๋ผ.
ํ์ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ์์ ์ฑ๊ณผ ์ ๋ขฐ์ฑ์ด ํฌ๊ฒ ํฅ์๋ผ. ์๋ชป๋ ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ฏธ๋ฆฌ ๋ง์ ์ ์์ผ๋๊น ๋ฒ๊ทธ๋ฅผ ์ค์ด๋ ๋ฐ ํฐ ๋์์ด ๋์ง. ๊ฒ๋ค๊ฐ ์ฝ๋๋ฅผ ์ฝ๋ ์ฌ๋์๊ฒ๋ ๊ฐ ์์ฑ์ด ์ด๋ค ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ผ ํ๋์ง ๋ช ํํ๊ฒ ์๋ ค์ค ์ ์์ด.
๐ ๋์ ๊ณผ์ : 'Person' ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ๋? 'name'(๋ฌธ์์ด), 'age'(0๋ณด๋ค ํฐ ์ ์), 'email'(์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ ํ์), 'hobbies'(๋ฌธ์์ด ๋ฐฐ์ด) ์์ฑ์ ๊ฐ์ง๋๋ก ํด๋ด. ํ์ ์ ์ฝ ์กฐ๊ฑด์ ๊ผญ ์ฌ์ฉํด์ผ ํด!
์, ์ด์ Moose์ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ๋ํด ์์๋ดค์ด. ์ด ๊ธฐ๋ฅ์ ์ ํ์ฉํ๋ฉด ๋ ์์ ํ๊ณ ๋ฏฟ์ ์ ์๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ ๊ฑฐ์ผ. ํ์ง๋ง ๋๋ฌด ๋ณต์กํ ์ ์ฝ ์กฐ๊ฑด์ ์คํ๋ ค ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ผ๋ ์ ์ ํ ์ฌ์ฉํ๋ ๊ฒ ์ค์ํด.
๋ค์ ์น์ ์์๋ Moose์ ๋ ๋ค๋ฅธ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ธ '๋ฉํํ๋ก๊ทธ๋๋ฐ'์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐งโโ๏ธ Moose์ ๋ฉํํ๋ก๊ทธ๋๋ฐ ๋ง๋ฒ
์๋ , ์น๊ตฌ๋ค! ์ด์ ์ฐ๋ฆฌ๋ Moose์ ๊ฐ์ฅ ๊ฐ๋ ฅํ๊ณ ํฅ๋ฏธ๋ก์ด ๊ธฐ๋ฅ ์ค ํ๋์ธ '๋ฉํํ๋ก๊ทธ๋๋ฐ'์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ๋ฉํํ๋ก๊ทธ๋๋ฐ์ด ๋ญ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ? ๊ฑฑ์ ๋ง, ์ฝ๊ฒ ์ค๋ช ํด์ค๊ฒ! ๐
๋ฉํํ๋ก๊ทธ๋๋ฐ์ ํ๋ก๊ทธ๋จ์ด ์๊ธฐ ์์ ์ ์์ ํ๊ฑฐ๋ ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ ๋ง๋ค์ด๋ด๋ ๊ธฐ์ ์ด์ผ. ์ฝ๊ฒ ๋งํด, ์ฝ๋๊ฐ ์ฝ๋๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฑฐ์ง. ๋ง์น ๋ง๋ฒ์ฌ๊ฐ ์ฃผ๋ฌธ์ ์ธ์ ์๋ก์ด ๋ง๋ฒ์ ๋ง๋ค์ด๋ด๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ! ๐งโโ๏ธโจ
Moose๋ ์ ๋ง ๊ฐ๋ ฅํ ๋ฉํํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํด. ์ด๋ฅผ ํตํด ์ฐ๋ฆฌ๋ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๊ฑฐ๋, ์๋ก์ด ๋ฉ์๋๋ฅผ ์คํ ์ค์ ์ถ๊ฐํ ์ ์์ด. ์ ๋ง ๋ฉ์ง์ง ์์?
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. ์ฐ๋ฆฌ๊ฐ ๋ง๋ 'Dog' ํด๋์ค์ ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ ์ฉํด๋ณด์:
package Dog;
use Moose;
extends 'Animal';
has 'breed' => (is => 'rw', isa => 'Str');
# ๋ฉํํด๋์ค ์ ๊ทผ
my $meta = __PACKAGE__->meta;
# ์๋ก์ด ์์ฑ ๋์ ์ถ๊ฐ
$meta->add_attribute('favorite_toy' => (
is => 'rw',
isa => 'Str',
));
# ์๋ก์ด ๋ฉ์๋ ๋์ ์ถ๊ฐ
$meta->add_method('play' => sub {
my $self = shift;
print $self->name . " is playing with " . $self->favorite_toy . "!\n";
});
1;
์ฐ์, ์ด๊ฒ ๋ญ๊น? ํ๋์ฉ ์ค๋ช ํด์ค๊ฒ:
my $meta = __PACKAGE__->meta;
: ์ด๊ฑด ํ์ฌ ํด๋์ค์ ๋ฉํ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฑฐ์ผ. ๋ฉํ๊ฐ์ฒด๋ฅผ ํตํด ์ฐ๋ฆฌ๋ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ์กฐ์ํ ์ ์์ด.$meta->add_attribute('favorite_toy' => ...);
: ์ด๊ฑด 'favorite_toy'๋ผ๋ ์๋ก์ด ์์ฑ์ ๋์ ์ผ๋ก ์ถ๊ฐํ๋ ๊ฑฐ์ผ.$meta->add_method('play' => sub { ... });
: ์ด๊ฑด 'play'๋ผ๋ ์๋ก์ด ๋ฉ์๋๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ๋ ๊ฑฐ์ผ.
์ด๋ ๊ฒ ํ๋ฉด ์ฐ๋ฆฌ๋ ์คํ ์ค์ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ด. ์ ๋ง ๊ฐ๋ ฅํ์ง ์์? ์ด์ 'Dog' ํด๋์ค๋ 'favorite_toy' ์์ฑ๊ณผ 'play' ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ฒ ๋์ด!
๐ฉ ๋ง๋ฒ์ฌ์ ํ: ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋จ์ฉํ๋ฉด ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ด. ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ๋ ๊ฒ ์ข์!
๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ฌ์ฉํ๋ฉด ์ ๋ง ์ ์ฐํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ด. ์๋ฅผ ๋ค์ด, ํ๋ฌ๊ทธ์ธ ์์คํ ์ ๋ง๋ค๊ฑฐ๋, ์ค์ ํ์ผ์ ๋ฐ๋ผ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๋ฑ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ง.
Moose์ ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ฌ๊ธฐ์ ๋์ด ์๋์ผ. ์ฐ๋ฆฌ๋ ํด๋์ค์ ๋ชจ๋ ์์ฑ์ ์ํํ๊ฑฐ๋, ํน์ ๋ฉ์๋๊ฐ ์กด์ฌํ๋์ง ํ์ธํ๊ฑฐ๋, ์ฌ์ง์ด ์ ์ฒด ํด๋์ค ๊ตฌ์กฐ๋ฅผ ํ๋ก๊ทธ๋๋ฐ์ ์ผ๋ก ๋ถ์ํ ์๋ ์์ด. ์ด๊ฑด ๋ง์น ๋ง๋ฒ์ฌ๊ฐ ์์ ์ ๋ง๋ฒ์ฑ ์ ์ฝ๊ณ ์์ ํ๋ ๊ฒ๊ณผ ๊ฐ์!
์ ๊ทธ๋ฆผ์ Moose์ ๋ฉํํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฅ์ ์๊ฐ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๊ณ ์์ด. ์ฐ๋ฆฌ๋ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋ถ์ํ๊ณ , ์๋ก์ด ์์ฑ๊ณผ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ณ , ์ฌ์ง์ด ์ ์ฒด ํด๋์ค ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์๋ ์์ง. ์ด๋ฐ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ค์ด Moose๋ฅผ ์ ๋ง ์ ์ฐํ๊ณ ๊ฐ๋ ฅํ ๋๊ตฌ๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฑฐ์ผ.
๋ฉํํ๋ก๊ทธ๋๋ฐ์ ๋ง์คํฐํ๋ฉด, ๋น์ ์ ์ง์ ํ Perl ๋ง๋ฒ์ฌ๊ฐ ๋ ์ ์์ด! ํ์ง๋ง ํฐ ํ์๋ ํฐ ์ฑ ์์ด ๋ฐ๋ฅธ๋ค๋ ๊ฑธ ์์ง ๋ง. ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํด. ๋จ์ฉํ๋ฉด ์ฝ๋๊ฐ ๋ณต์กํด์ง๊ณ ์ดํดํ๊ธฐ ์ด๋ ค์์ง ์ ์๊ฑฐ๋ .
๐ง ์๊ฐํด๋ณด๊ธฐ: ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ด๋ค ์ํฉ์์ ์ฌ์ฉํ๋ฉด ์ข์๊น? ์๋ฅผ ๋ค์ด, ์ค์ ํ์ผ์ ๋ฐ๋ผ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ํ๋ก๊ทธ๋จ์ ๋ง๋ ๋ค๋ฉด ์ด๋จ๊น? ๋๋ ํ๋ฌ๊ทธ์ธ ์์คํ ์ ๊ตฌํํ๋ค๋ฉด?
์, ์ด์ Moose์ ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ๋ํด ์์๋ดค์ด. ์ด ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ง ์ ์ฐํ๊ณ ๋์ ์ธ ํ๋ก๊ทธ๋จ์ ๋ง๋ค ์ ์์ด. ํ์ง๋ง ํญ์ ๊ธฐ์ตํด์ผ ํ ๊ฑด, ๋ณต์ก์ฑ๊ณผ ์ ์ฐ์ฑ ์ฌ์ด์ ๊ท ํ์ ์ ๋ง์ถ๋ ๊ฒ ์ค์ํ๋ค๋ ๊ฑฐ์ผ.
๋ค์ ์น์ ์์๋ Moose์ 'Role' ๊ธฐ๋ฅ์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. Role์ ๋ค์ค ์์์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ฉด์๋ ์ฝ๋ ์ฌ์ฌ์ฉ์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๋ฉ์ง ๊ธฐ๋ฅ์ด์ง. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐ญ Moose์ Role: ์ฝ๋ ์ฌ์ฌ์ฉ์ ์๋ก์ด ํจ๋ฌ๋ค์
์๋ , ์น๊ตฌ๋ค! ์ด์ ์ฐ๋ฆฌ๋ Moose์ ๋ ๋ค๋ฅธ ๋ฉ์ง ๊ธฐ๋ฅ์ธ 'Role'์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. Role์ด ๋ญ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ? ๊ฑฑ์ ๋ง, ์ฝ๊ฒ ์ค๋ช ํด์ค๊ฒ! ๐
Role์ ๋ฉ์๋์ ์์ฑ์ ์งํฉ์ผ๋ก, ํด๋์ค์ 'ํผํฉ(mix in)'๋ ์ ์์ด. ์ฝ๊ฒ ๋งํด, Role์ ํด๋์ค๊ฐ ์ํํ ์ ์๋ ๋ฅ๋ ฅ์ด๋ ์ฑ ์์ ๋ํ๋ด๋ ๊ฑฐ์ผ. ๋ง์น ๋ฐฐ์ฐ๊ฐ ์ฐ๊ทน์์ ์ฌ๋ฌ ์ญํ ์ ๋งก๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ! ๐ญ
Role์ ๋ค์ค ์์์ ๋ฌธ์ ์ (์: ๋ค์ด์๋ชฌ๋ ๋ฌธ์ )์ ํด๊ฒฐํ๋ฉด์๋ ์ฝ๋ ์ฌ์ฌ์ฉ์ ๊ฐ๋ฅํ๊ฒ ํด์ค. ์ ๋ง ๋ฉ์ง์ง ์์?
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. 'Swimmer'์ 'Runner' Role์ ๋ง๋ค๊ณ , ์ด๋ฅผ 'Athlete' ํด๋์ค์ ์ ์ฉํด๋ณด์:
package Swimmer;
use Moose::Role;
has 'swimming_speed' => (is => 'rw', isa => 'Int');
sub swim {
my $self = shift;
print "Swimming at speed " . $self->swimming_speed . "!\n";
}
package Runner;
use Moose::Role;
has 'running_speed' => (is => 'rw', isa => 'Int');
sub run {
my $self = shift;
print "Running at speed " . $self->running_speed . "!\n";
}
package Athlete;
use Moose;
with 'Swimmer', 'Runner';
has 'name' => (is => 'rw', isa => 'Str');
1;
์ฐ์, ์ด๊ฒ ๋ญ๊น? ํ๋์ฉ ์ค๋ช ํด์ค๊ฒ:
use Moose::Role;
: ์ด๊ฑด Role์ ์ ์ํ๊ธฐ ์ํด ์ฌ์ฉํด.with 'Swimmer', 'Runner';
: ์ด๊ฑด 'Athlete' ํด๋์ค์ 'Swimmer'์ 'Runner' Role์ ์ ์ฉํ๋ ๊ฑฐ์ผ.
์ด๋ ๊ฒ ํ๋ฉด 'Athlete' ํด๋์ค๋ 'Swimmer'์ 'Runner' Role์ ๋ชจ๋ ๋ฉ์๋์ ์์ฑ์ ๊ฐ์ง๊ฒ ๋ผ. ์ฆ, 'Athlete' ๊ฐ์ฒด๋ 'swim'๊ณผ 'run' ๋ฉ์๋๋ฅผ ๋ชจ๋ ์ฌ์ฉํ ์ ์์ด!
๐โโ๏ธ๐โโ๏ธ ์ด๋์ ์์ ํ: Role์ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ๋ ๋ชจ๋ํํ๊ณ ์ฌ์ฌ์ฉํ ์ ์์ด. ์๋ฅผ ๋ค์ด, 'Swimmer' Role์ด ํ์ํ ๋ค๋ฅธ ํด๋์ค(์: 'Lifeguard')์๋ ์ฝ๊ฒ ์ ์ฉํ ์ ์์ง!
Role์ ๋ ๋ค๋ฅธ ์ฅ์ ์ ์ถฉ๋ ํด๊ฒฐ ๋ฉ์ปค๋์ฆ์ด์ผ. ๋ง์ฝ ๋ ๊ฐ์ Role์ด ๊ฐ์ ์ด๋ฆ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด, Moose๋ ์ปดํ์ผ ์์ ์๋ฌ๋ฅผ ๋ฐ์์์ผ. ์ด๋ ๊ฒ ํ๋ฉด ์์์น ๋ชปํ ๋์์ ๋ฏธ๋ฆฌ ๋ฐฉ์งํ ์ ์์ด.
Role์ ์ถ์ ํด๋์ค๋ ์ธํฐํ์ด์ค์ ๋น์ทํ์ง๋ง, ๋ ์ ์ฐํ๊ณ ๊ฐ๋ ฅํด. Role์ ๊ตฌํ์ ํฌํจํ ์ ์๊ณ , ์ฌ๋ฌ ๊ฐ๋ฅผ ๋์์ ์ ์ฉํ ์ ์๊ฑฐ๋ .
์ ๊ทธ๋ฆผ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ Role๊ณผ ํด๋์ค์ ๊ตฌ์กฐ๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์์ด. 'Swimmer'์ 'Runner' Role์ด 'Athlete' ํด๋์ค์ ์ ์ฉ๋๋ ๊ฑธ ๋ณผ ์ ์์ง. ์ด๋ ๊ฒ Role์ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ๋ ๋ชจ๋ํํ๊ณ ์ฌ์ฌ์ฉํ ์ ์์ด.
Role์ ์ฌ์ฉํ๋ฉด "๋ค์ค ์์"์ ์ฅ์ ์ ์ด๋ฆฌ๋ฉด์ ๋จ์ ์ ํผํ ์ ์์ด. ๊ฒ๋ค๊ฐ ์ฝ๋์ ๊ตฌ์กฐ๋ฅผ ๋ ๋ช ํํ๊ฒ ๋ง๋ค์ด์ฃผ์ง. ๊ฐ Role์ ํน์ ํ ๋ฅ๋ ฅ์ด๋ ์ฑ ์์ ๋ํ๋ด๋๊น, ํด๋์ค์ ์ค๊ณ๊ฐ ๋ ์ง๊ด์ ์ด๊ณ ์ดํดํ๊ธฐ ์ฌ์์ ธ.
๐ง ์๊ฐํด๋ณด๊ธฐ: Role์ ์ด๋ค ์ํฉ์์ ์ฌ์ฉํ๋ฉด ์ข์๊น? ์๋ฅผ ๋ค์ด, ์ฌ๋ฌ ํด๋์ค์์ ๊ณตํต์ผ๋ก ์ฌ์ฉ๋๋ ๊ธฐ๋ฅ์ด ์๋ค๋ฉด? ๋๋ ํด๋์ค๊ฐ ์ฌ๋ฌ ๊ฐ์ง ์ญํ ์ ์ํํด์ผ ํ๋ค๋ฉด?
์, ์ด์ Moose์ Role์ ๋ํด ์์๋ดค์ด. Role์ ์ ํ์ฉํ๋ฉด ์ฝ๋๋ฅผ ๋ ๋ชจ๋ํํ๊ณ , ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๊ณ , ์ ์ง๋ณด์๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด. ํ์ง๋ง ํญ์ ๊ธฐ์ตํด์ผ ํ ๊ฑด, ์ ์ ํ ๊ณณ์ ์ ์ ํ๊ฒ ์ฌ์ฉํ๋ ๊ฒ ์ค์ํ๋ค๋ ๊ฑฐ์ผ.
์ฐ๋ฆฌ๋ ์ง๊ธ๊น์ง Moose์ ์ฃผ์ ๊ธฐ๋ฅ๋ค์ ์ดํด๋ดค์ด. ํด๋์ค์ ๊ฐ์ฒด ์์ฑ, ์์, ํ์ ์ ์ฝ ์กฐ๊ฑด, ๋ฉํํ๋ก๊ทธ๋๋ฐ, ๊ทธ๋ฆฌ๊ณ Role๊น์ง. ์ด ๋ชจ๋ ๊ธฐ๋ฅ๋ค์ด Moose๋ฅผ ์ ๋ง ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์์คํ ์ผ๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฑฐ์ผ.
Moose๋ฅผ ๋ง์คํฐํ๋ฉด, ๋น์ ์ Perl๋ก ์ ๋ง ๋ฉ์ง ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋จ์ ๋ง๋ค ์ ์์ ๊ฑฐ์ผ. ๋ณต์กํ ์์คํ ๋ ๊น๋ํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ก ๊ตฌํํ ์ ์์ง. ๊ทธ๋ฆฌ๊ณ ์ด๋ฐ ๊ธฐ์ ์ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ๋ฐฐ์ธ ๋๋ ํฐ ๋์์ด ๋ ๊ฑฐ์ผ.
์, ์ด์ ์ฐ๋ฆฌ์ Moose ์ฌํ์ด ๋๋๊ฐ๊ณ ์์ด. ๋ง์ง๋ง์ผ๋ก, Moose๋ฅผ ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง, ๊ทธ๋ฆฌ๊ณ ์ฃผ์ํด์ผ ํ ์ ์ ๋ฌด์์ธ์ง ์ ๋ฆฌํด๋ณผ๊ฒ. ์ค๋น๋๋? ๊ทธ๋ผ ๊ณ์ ๊ฐ๋ณด์!
๐ Moose ๋ง์คํฐํ๊ธฐ: ์ค์ ํ๊ณผ ์ฃผ์์ฌํญ
์๋ , ์น๊ตฌ๋ค! ์ฐ๋ฆฌ์ Moose ์ฌํ์ด ๊ฑฐ์ ๋๋๊ฐ๊ณ ์์ด. ์ด์ Moose๋ฅผ ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง, ๊ทธ๋ฆฌ๊ณ ์ฃผ์ํด์ผ ํ ์ ์ ๋ฌด์์ธ์ง ์ ๋ฆฌํด๋ณผ๊ฒ. ์ด๊ฑด ์ ๋ง ์ค์ํ๋๊น ์ ๋ค์ด๋ด! ๐
๐ Moose ํ์ฉ ํ
- ๋ชจ๋ํ๋ฅผ ๊ทน๋ํํ์ธ์: Role์ ์ ๊ทน์ ์ผ๋ก ํ์ฉํด ์ฝ๋๋ฅผ ์์ ๋จ์๋ก ๋๋์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ด ๋์์ง๊ณ ์ ์ง๋ณด์๊ฐ ์ฌ์์ ธ์.
- ํ์ ์ ์ฝ ์กฐ๊ฑด์ ํ์ฉํ์ธ์: ๊ฐ๋ฅํ ํ ๋ชจ๋ ์์ฑ์ ํ์ ์ ์ฝ ์กฐ๊ฑด์ ๊ฑธ์ด์ฃผ์ธ์. ์ด๋ ๋ฒ๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐฉ์งํ๊ณ ์ฝ๋์ ์์ ์ฑ์ ๋์ฌ์ค์.
- ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ์ ์คํ๊ฒ ์ฌ์ฉํ์ธ์: ๋ฉํํ๋ก๊ทธ๋๋ฐ์ ๊ฐ๋ ฅํ์ง๋ง, ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ์ฝ๋๊ฐ ๋ณต์กํด์ง ์ ์์ด์. ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ์ธ์.
- ๋ฌธ์ํ๋ฅผ ์ ํ์ธ์: Moose๋ ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์, ๊ฐ ํด๋์ค์ Role์ ๋ชฉ์ ๊ณผ ์ฌ์ฉ๋ฒ์ ๋ช ํํ ๋ฌธ์ํํ๋ ๊ฒ์ด ์ค์ํด์.
โ ๏ธ ์ฃผ์์ฌํญ
- ์ฑ๋ฅ์ ์ฃผ์ํ์ธ์: Moose๋ ๋งค์ฐ ๊ฐ๋ ฅํ์ง๋ง, ๋๋ก๋ ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ์์ ์ ์์ด์. ์ฑ๋ฅ์ด ์ค์ํ ๋ถ๋ถ์์๋ ํ๋กํ์ผ๋ง์ ํตํด ์ต์ ํ๋ฅผ ๊ณ ๋ คํด๋ณด์ธ์.
- ๊ณผ๋ํ ์ถ์ํ๋ฅผ ํผํ์ธ์: Moose์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋งค๋ฃ๋์ด ๋ถํ์ํ๊ฒ ๋ณต์กํ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ง ์๋๋ก ์ฃผ์ํ์ธ์. ๊ฐ๋จํจ์ด ์ต๊ณ ์์!
- ๋ฒ์ ํธํ์ฑ์ ํ์ธํ์ธ์: Moose์ ๊ทธ ์์กด์ฑ ๋ชจ๋๋ค์ ๋ฒ์ ์ ์ ๊ด๋ฆฌํ์ธ์. ๋ฒ์ ์ฐจ์ด๋ก ์ธํ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ด์.
๐ก ํ๋ก ํ: Moose๋ฅผ ์ฒ์ ์ฌ์ฉํ ๋๋ ๊ธฐ์กด์ ์ ์ค๊ณ๋ Moose ๊ธฐ๋ฐ ํ๋ก์ ํธ๋ค์ ๋ถ์ํด๋ณด๋ ๊ฒ์ด ์ข์์. ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ ๊ฒฝํ์์ ๋ง์ ๊ฒ์ ๋ฐฐ์ธ ์ ์๋ต๋๋ค!
Moose๋ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๊ฒ์ ์๋์์. ์์ ์คํฌ๋ฆฝํธ๋ ๊ฐ๋จํ ํ๋ก๊ทธ๋จ์๋ ๊ณผ๋ํ ์ ์์ฃ . ํ๋ก์ ํธ์ ๊ท๋ชจ์ ๋ณต์ก์ฑ์ ๊ณ ๋ คํด์ Moose ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ์ธ์.
๋ง์ง๋ง์ผ๋ก, Moose ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํด๋ณด๋ ๊ฒ์ ์ด๋จ๊น์? CPAN(Comprehensive Perl Archive Network)์๋ ์๋ง์ Moose ๊ด๋ จ ๋ชจ๋๋ค์ด ์์ด์. ์ด๋ค์ ํํํ๊ณ , ํ์ํ๋ค๋ฉด ๊ธฐ์ฌํด๋ณด์ธ์. ์คํ ์์ค ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ๋ ๊ฒ์ ์ ๋ง ๊ฐ์ง ๊ฒฝํ์ด ๋ ๊ฑฐ์์!
์ ๊ทธ๋ฆผ์ Moose ๋ง์คํฐ๊ฐ ๋๊ธฐ ์ํ ๋ก๋๋งต์ ๋ณด์ฌ์ฃผ๊ณ ์์ด์. ๊ธฐ๋ณธ ๊ฐ๋ ์ ํ์ตํ๊ณ , ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด๊ณ , ๊ณ ๊ธ ๊ธฐ๋ฅ์ ํํํ๊ณ , ๋ง์ง๋ง์ผ๋ก ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ๋ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด ๋ผ์. ๊ฐ ๋จ๊ณ๋ง๋ค ์๋ก์ด ๋์ ๊ณผ ๋ฐฐ์์ด ๊ธฐ๋ค๋ฆฌ๊ณ ์์ ๊ฑฐ์์!
Moose๋ฅผ ๋ง์คํฐํ๋ ์ฌ์ ์ ๋์ด ์์ด์. ํญ์ ์๋ก์ด ๊ฒ์ ๋ฐฐ์ฐ๊ณ , ๋ ๋์ ์ฝ๋๋ฅผ ์์ฑํ๋ ค๊ณ ๋ ธ๋ ฅํ์ธ์. ๊ทธ๋ฆฌ๊ณ ๊ฐ์ฅ ์ค์ํ ๊ฑด, ์ฝ๋ฉ์ ์ฆ๊ธฐ๋ ๊ฑฐ์์! Moose๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๋ฌธ์ ๋ ์ฌ๋ฏธ์๊ฒ ํด๊ฒฐํ ์ ์์ ๊ฑฐ์์.
๐ ์ถํํด์! ์ฌ๋ฌ๋ถ์ ์ด์ Moose์ ๊ธฐ๋ณธ๋ถํฐ ๊ณ ๊ธ ๊ธฐ๋ฅ๊น์ง ๋ชจ๋ ๋ฐฐ์ ์ด์. ์ด์ ์ฌ๋ฌ๋ถ์ Perl๋ก ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋จ์ ๋ง๋ค ์ ์๋ ์ค๋น๊ฐ ๋์์ด์. ๋จ์ ๊ฑด ์ค์ ๊ฒฝํ๋ฟ์ด์์. ์, ์ด์ ์ฌ๋ฌ๋ถ๋ง์ ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ์์ํด๋ณด์ธ์!
Moose์ ํจ๊ปํ๋ ์ฌ์ ์ด ์ฌ๋ฌ๋ถ์๊ฒ ์ฆ๊ฒ๊ณ ์ ์ตํ๊ธฐ๋ฅผ ๋ฐ๋ผ์. ์์ผ๋ก Perl๋ก ์ฝ๋ฉํ ๋ Moose๊ฐ ํฐ ๋์์ด ๋ ๊ฑฐ์์. ํญ์ ์๋ก์ด ๊ฒ์ ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ๊ฐ๋ฐ์๊ฐ ๋์ธ์. ํ์ดํ ! ๐จโ๐ป๐ฉโ๐ป
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ