Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NestJSのDIコンテナで作るクリーンなレイヤー境界
Search
kimutyam
May 20, 2022
Technology
2
1.9k
NestJSのDIコンテナで作るクリーンなレイヤー境界
NestJS Meetup Online #2 にて発表した内容です。
https://nest-jp.connpass.com/event/244015/
kimutyam
May 20, 2022
Tweet
Share
More Decks by kimutyam
See All by kimutyam
Embulk / Presto / Sparkを用いたETL事情
kimutyam
4
2.1k
セプテーニで分析基盤(Treasure Data)を導入した話
kimutyam
0
1.5k
Reactive Messaging Patternsを使った境界づけられたコンテキストの統合
kimutyam
3
1.3k
アジャイルでのドメイン・ユースケースモデリング
kimutyam
5
2.2k
Introduction of ScalaTest
kimutyam
3
2.2k
Scalaで学ぶヘキサゴナルアーキテクチャ実践入門
kimutyam
15
6.7k
Other Decks in Technology
See All in Technology
PHPカンファレンス名古屋-テックリードの経験から学んだ設計の教訓
hayatokudou
2
540
AWSアカウントのセキュリティ自動化、どこまで進める? 最適な設計と実践ポイント
yuobayashi
7
470
エンジニアが加速させるプロダクトディスカバリー 〜最速で価値ある機能を見つける方法〜 / product discovery accelerated by engineers
rince
4
560
OSS構成管理ツールCMDBuildを使ったAWSリソース管理の自動化
satorufunai
0
570
Active Directory攻防
cryptopeg
PRO
8
5.3k
システム・ML活用を広げるdbtのデータモデリング / Expanding System & ML Use with dbt Modeling
i125
1
320
コンピュータビジョンの社会実装について考えていたらゲームを作っていた話
takmin
1
590
Oracle Database Technology Night #87-1 : Exadata Database Service on Exascale Infrastructure(ExaDB-XS)サービス詳細
oracle4engineer
PRO
1
120
プロダクトエンジニア 360°フィードバックを実施した話
hacomono
PRO
0
140
あなたが人生で成功するための5つの普遍的法則 #jawsug #jawsdays2025 / 20250301 HEROZ
yoshidashingo
2
240
ディスプレイ広告(Yahoo!広告・LINE広告)におけるバックエンド開発
lycorptech_jp
PRO
0
280
エンジニアリング価値を黒字化する バリューベース戦略を用いた 技術戦略策定の道のり
kzkmaeda
6
2.3k
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
100
18k
A Philosophy of Restraint
colly
203
16k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
193
16k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Speed Design
sergeychernyshev
27
810
We Have a Design System, Now What?
morganepeng
51
7.4k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
114
50k
Unsuck your backbone
ammeep
669
57k
Gamification - CAS2011
davidbonilla
80
5.2k
Git: the NoSQL Database
bkeepers
PRO
427
65k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Transcript
גࣜձࣾΧέϋγɹଜজ /FTU+4ͷ%*ίϯςφͰ࡞ΔΫϦʔϯͳϨ ΠϠʔڥք /FTU+4NFFUVQ0OMJOFɹ
ࢹௌऀɾಡऀͷఆ w ҎԼͷ͍ͣΕ͔ʹ֘ w /FTU+4Ͱ8FCΞϓϦέʔγϣϯΛΜͩ͜ͱ͕͋Δ w /FTU+4ͷ1SPWJEFS.PEVMFΛ৮ͬͨ͜ͱ͕͋Δ w ΦϒδΣΫτࢦͰͷઃܭɾ։ൃܦݧ͕͋Δ
ࣗݾհ w גࣜձࣾΧέϋγ d w ҩྍൃɾཧ࠷దԽྖҬͷ৽نࣄۀͷ্ཱͪ͛Λ୲த w ιϑτΣΞΤϯδχΞσʔλΤϯδχΞΞʔΩςΫτ w
Χέϋγͱ5ZQF4DSJQU w גࣜձࣾΧέϋγY5ZQF4DSJQU"EWFOU$BMFOEBS w ͳͥόοΫΤϯυ5ZQF4DSJQU͔ʁٕज़બఆഎܠͱ࣮ફྫΛհ͠·͢ ଜজ ͖ΉΒ͖͋ͻΖ ˞ܦྺͷৄࡉ/FTU+4.FFUVQ0OMJOFͷΠϕϯτϖʔδʹهࡌ͍ͯ͠·͢
5XJUUFSIUUQTUXJUUFSDPNLJNVUZBN .FEJVNIUUQTLJNVUZBNNFEJVNDPN 4QFBLFS%FDLIUUQTTQFBLFSEFDLDPNLJNVUZBN (JUIVCIUUQTHJUIVCDPNLJNVUZBN 'PMMPX.F
ΞδΣϯμ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ /FTU+4ͷ%*ίϯςφͷΈ ϨΠϠʔڥքΛߏ͢Δ औΓѻΘͳ͍͜ͱ w ΫϦʔϯΞʔΩςΫνϟͷਂ͍આ໌
w υϝΠϯϞσϦϯάͷํ ηΫγϣϯ
ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ ͑ํ ηΫγϣϯ
w ΫϦʔϯΞʔΩςΫνϟͰ༗໊ͳਤͰ͢ɻ w ͜ΕΒͷಉ৺ԁͷଆʹ͍͘΄ͲιϑτΣΞͱ ্ͯ͠ҐϞδϡʔϧʹͳΔ͜ͱ͕ࣔ͞Ε͍ͯ·͢ɻ w υϝΠϯۦಈઃܭͷจ຺ͩͱɺ&OUJUJFTศ্ٓυ ϝΠϯϞσϧͱදݱ͢Δ߹͕͋Γ·͢ɻ w ಉ৺ԁͷΛϨΠϠʔڥքͱݺͼ·͢ɻ
w ಉ৺ԁͷΛԣஅ͢ΔʮˠʯґଘؔͰ͢ɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ΫϦʔϯΞʔΩςΫνϟ IUUQTCMPHDMFBODPEFSDPNVODMFCPCUIFDMFBOBSDIJUFDUVSFIUNM
ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ґଘؔٯసͷݪଇ %FQFOEFODZ*OWFSTJPO1SJODJQMF l্ҐϞδϡʔϧ͍͔ͳΔͷԼҐϞδϡʔϧ ͔Β࣋ͪࠐΜͰͳΒͳ͍ɻํͱநʢྫͱ͠ ͯΠϯλʔϑΣʔεʣʹґଘ͢Δ͖Ͱ͋Δɻz˞ lநৄࡉʹґଘͯ͠ͳΒͳ͍ɻৄࡉʢ۩త ͳ࣮༰ʣ͕நʹґଘ͢Δ͖Ͱ͋Δɻz˞ ґଘؔٯసύλʔϯͰɺΠϯλʔϑΣʔεΛհ ͤ͞Δ͜ͱͰ্ҐϞδϡʔϧͷґଘΛճආ͍ͯ͠·
͢ɻ ,MPESߘऀࣗʹΑΔஶ࡞ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJEʹΑΔ ,MPESߘऀࣗʹΑΔஶ࡞ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJEʹΑΔ ӈ্ը૾ ӈԼը૾ ˞ IUUQTKBXJLJQFEJBPSHXJLJґଘੑٯసͷݪଇ ैདྷͷϨΠϠʔύλʔϯ ґଘؔٯసύλʔϯ
w ґଘؔٯసͷݪଇʹैͬͨઃܭΛ͢Δͱɺ࠷ऴ తʹΠϯλʔϑΣʔεͷ࣮Λඥ͚Δඞཁ͕ग़ͯ ͖·͢ɻͦ͜Ͱɺґଘੑͷೖ %* Λߦ͍·͢ɻ w ্ͷίʔυɺίϯετϥΫλͰґଘੑΛೖ͢ ΔྫͰ͢ ίϯετϥΫλ%*
ɻ w %*ͱɺґଘؔΛΫϥεؔͷ֎͔Β͢͜ͱ Ͱ͢ɻ w ͳ͓ɺԼͷίʔυɺ.FDIBOJTN෦Ͱ1PMJDZͷ ۩Ϋϥε͕ґଘͯ͠ɺґଘੑͷzೖzʹͳͬͯ ͍·ͤΜɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ґଘੑͷೖ %FQFOEFODZ*OKFDUJPO export class MechanismService { constructor(private policyService: IPolicyService) { } // ུ } export class MechanismService { private policyService: IPolicyService = new PolicyService( ) // ུ }
w %*ΛͬͨΫϥεઃܭΛਐΊΔͱɺґଘؔΛղ ܾ͢ΔӈͷΑ͏ͳίʔυ͕ੜ·Ε·͢ɻ w Ϋϥε͕গͳ͍͏ͪʹͳΓ·ͤΜ͕ɺ૿͑ ͖ͯͨ࣌ෆཁͳෳࡶੑΛੜΉ߹͕͋Γ·͢ɻ w %*ίϯςφӈͷίʔυΛॻ͔ͣʹґଘؔͷϏ δωεϩδοΫͷ֎ଆͰཧ͢Δ͜ͱ͕Ͱ͖· ͢ɻ
w ͦͯ͠ɺ%*ίϯςφ/FTU+4ͷओཁͳػೳͷͭ Ͱ͢ɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ %*ίϯςφԿΛղܾ͢Δ͔ʁ new UtilityService ( new MechanismService ( new PolicyService( ) ) )
/FTU+4ͷ%*ίϯςφͷΈ ηΫγϣϯ
w ·ͣ؆୯ͳྫ͔Βɻ w $BUT4FSWJDFͷґଘؔɺ!.PEVMFΛӈͷΑ͏ ʹఆٛ͢Ε%*Ͱ͖·͢ɻ w ͜ͷྫɺ$BUT4FSWJDFzΫϥεzΛ$BUT$POUSPMMFS ͰίϯετϥΫλ%*͍ͯ͠·͢ɻ /FTU+4ͷ%*ίϯςφͷΈ 1SPWJEFS
@Controlle r class CatsService { } @Controller("cats") class CatsController { constructor(private catsService: CatsService) { } // ུ } @Module( { controllers: [CatsController] , providers: [CatsService] , } ) export class AppModule {}
w ΠϯλʔϑΣʔεͷ߹ɺ͕ඞཁͰ͢ɻ w +BWB4DSJQUΠϯλʔϑΣʔεΛαϙʔτͯ͠ ͍ͳ͍ͨΊɺ5ZQF4DSJQUΛ+BWB4DSJQUʹίϯ ύΠϧ͢ΔͱɺΠϯλʔϑΣʔεͷఆٛফࣦ ͠·͢ɻ w τʔΫϯ ྫͰ$"54@4&37*$&@50,&/
Ͱ /FTU+4ͷ*OKFDUFSͰࣝผՄೳͳঢ়ଶʹ͢Δඞཁ͕ ͋Γ·͢ɻ /FTU+4ͷ%*ίϯςφͷΈ 1SPWJEFS interface ICatsService { } class CatsService implements ICatsService { } const CATS_SERVICE_TOKEN = "CATS_SERVICE_TOKEN" ; class CatsController { constructor ( @Inject(CATS_SERVICE_TOKEN ) private catsService: ICatsServic e ) { } // ུ } export const CatServiceProvider: Provider = { provide: CAT_SERVICE_TOKEN , useClass: CatsService , } ; @Module( { controllers: [CatsController] , providers: [CatServiceProvider] , } ) export class AppModule { }
/FTU+4ͷ%*ίϯςφͷΈ !.PEVMFͱԿ͔ʁ .PEVMF# .PEVMF" FYQPSUT JNQPSUT JNQPSUT 1SPWJEFS 1SPWJEFS $POUSPMMFS
QSPWJEFST /FTU+4ͷΠϯδΣΫλʹΑͬͯΠϯελϯ εԽ͞Εɺগͳ͘ͱϞδϡʔϧͰڞ༗ ͞ΕΔ DPOUSPMMFST .PEVMFͷΠϯελϯεԽ͢Δඞཁ͕͋Δ $POUSPMMFSҰཡ JNQPSUT ͜ͷϞδϡʔϧʹFYQPSU͢ΔผͷϞδϡʔ ϧͷҰཡ FYQPSUT ผͷϞδϡʔϧͰ͜ͷϞδϡʔϧΛJNQPSU ͢ΔͨΊͷɺެ։͢ΔϓϩόΠμٴͼτʔ ΫϯͷϦετ
ϨΠϠʔڥքΛߏ͢Δ ηΫγϣϯ
ϨΠϠʔڥքΛߏ͢Δ IUUQTCMPHDMFBODPEFSDPNVODMFCPCUIFDMFBOBSDIJUFDUVSFIUNM ߏ͢ΔΫϥεਤ
ϨΠϠʔڥքΛߏ͢Δ ߏ͢ΔΫϥεਤ w ֤ϨΠϠʔຖ EPNBJOVTF$BTF QSJNBSZ"EBQUPSTFDPOEBSZ"EBQUPS ʹͦΕͧ Ε.PEVMFΛ࡞͠·͢ w ͦΕΒΛ࠷ऴతʹ.PEVMFΛଋͶ·͢ɻ
w <ิ>QSJNBSZͱTFDPOEBSZͱʁ w ΫϦʔϯΞʔΩςΫνϟͷલਐͱͳͬͨ 1PSUT"EBQUPSTΞʔΩςΫνϟͷ༻ޠͰ ͢ɻ w QSJNBSZʮۦಈ͢ΔʯΞμϓλ w TFDPOEBSZʮۦಈ͞ΕΔʯΞμϓλ
w 3FQPTJUPSZ3FRVFTUFS*'ͷΈͰ͢ɻ w ۩ମతͳ࣮Λ͢ΔͱΞμϓλٴͼͦΕΑ Γ֎ͷԁʹґଘͯ͠͠·͏ͨΊͰ͢ɻ w Ұ൪্ҐϞδϡʔϧʹͳΔͨΊzೖz͢Δґଘ ͳ͍ͨΊɺ.PEVMF͋Γ·ͤΜɻ w ͳ͓ɺτʔΫϯϢʔεέʔεͷ࣮Ͱ͏ͨ
Ίɺ͜͜ʹஔ͍ͯ͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ υϝΠϯ EPNBJO export type Cat = Readonly< { id: CatId ; name: CatName ; age: CatAge ; }> ; export const CAT_REPOSITORY_TOKEN = 'CAT_REPOSITORY_TOKEN' ; export interface ICatRepository { store(cat: Cat): Promise<void> ; } export const CAT_REQUESTER_TOKEN = 'CAT_REQUESTER_TOKEN' ; export interface ICatRequester { get(catId: CatId): Promise<Cat | undefined> ; }
w ʮೣΛड͚औΔʯͱ͍͏ϢʔεέʔεΛఆͨ͠ ࣮Ͱ͢ɻ w 6TF$BTF*'Ͱɺͦͷ࣮Ϋϥε *OUFSBDUPS Ͱ͢ɻ w *OUFSBDUPSͰυϝΠϯͰఆٛͨ͠*'Λίϯε τϥΫλͷҾʹఆ͍ٛͯ͠·͢ɻ
ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF export interface UseCase<In, Out> { run(input: In): Promise<Out> ; } export type Input = Readonly< { catId: CatId ; }> ; export type Output = Omit<Cat, 'id'> ; export type ReceiveCatUseCase = UseCase<Input, Output> ; export const RECEIVE_CAT_USECASE_TOKEN = 'RECEIVE_CAT_USECASE_TOKEN' ; @Injectable( ) export class ReceiveCatInteractor implements ReceiveCatUseCase { constructor ( @Inject(CAT_REPOSITORY_TOKEN ) private catRepository: ICatRepository , @Inject(CAT_REQUESTER_TOKEN ) private catRequester: ICatRequester , ) { } async run({ catId }: Input): Promise<Output> { const cat = await this.catRequester.get(catId); // ུ } }
ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF w ηΧϯμϦʔΞμϓλͷΫϥε Λ࣮ͱͯ͠ ࠾༻͢Δ͜ͱʹ͢Δ߹ɺηΧϯμϦΞμϓλ ͷ.PEVMFΛJNQPSU͠·͢ɻ w
͜ΕΛ౿·͑ͯ࣍ͷϖʔδͰ.PEVMFΛ࡞͠ ·͢ɻ
w ηΧϯμϦʔΞμϓλͷ.PEVMF ޙड़ ΛJNQPSU ͍ͯ͠·͢ w ϢʔεέʔεΛଞͷ.PEVMFͰར༻Ͱ͖ΔΑ͏ʹ ϓϩόΠμΛFYQPSU͍ͯ͠·͢ w ϓϥΠϚϦΞμϓλͷ.PEVMF
ޙड़ ͰJNQPSU ͠·͢ɻ w <ิ>6TF$BTF.PEVMFΠϯλʔϑΣʔεΞμ ϓλʹґଘ͍ͯ͠·͕͢ɺϩδοΫ͕ґଘ͍ͯ͠ ΔΘ͚Ͱ͋Γ·ͤΜɻ ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF export const ReceiveCatUseCaseProvider: Provider = { provide: RECEIVE_CAT_USECASE_TOKEN , useClass: ReceiveCatInteractor , } ; @Module( { imports: [AdaptorMemoryStoreModule, AdaptorPetShopApiModule] , providers: [ReceiveCatUseCaseProvider] , exports: [ReceiveCatUseCaseProvider] , } ) export class UseCaseModule { }
w υϝΠϯͷϦϙδτϦͷ*'Λ࣮͍ͯ͠·͢ɻ w ϦϙδτϦͷϓϩόΠμΛଞͷ.PEVMFͰ׆༻Ͱ ͖ΔΑ͏ʹFYQPSU͍ͯ͠·͢ɻ w Ϣʔεέʔεͷ.PEVMFͰJNQPSU͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 4FDPOEBSZ"EBQUPS
@Injectable( ) export class CatRepository implements ICatRepository { store(cat: Cat): Promise<void> { // ུ } } export const CatRepositoryProvider: Provider = { provide: CAT_REPOSITORY_TOKEN , useClass: CatRepository , } ; @Module( { providers: [CatRepositoryProvider] , exports: [CatRepositoryProvider] , } ) export class AdaptorMemoryStoreModule { }
w $BU$POUSPMMFSͷ࣮Ͱ͢ɻ w 6TF$BTF*'ͱ1SFTFOUFSͷΫϥεΛίϯετ ϥΫλͰఆ͍ٛͯ͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS @Injector( )
export class CatPresenter { } @Controller('/cat' ) export class CatController { constructor ( @Inject(RECEIVE_CAT_USECASE_TOKEN ) private receiveCatUseCase: ReceiveCatUseCase , private catPresenter: CatPresenter , ) { } @Put(':id' ) async receive(@Param('id') id: string): Promise<CatViewModel> { // ུ } }
ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS w $POUSPMMFS ੨ ͷґଘؔΛղܾ͢ΔͨΊʹɺ *OUFSBDUPSͷϓϩόΠμʔΛؚΉϢʔεέʔεͷ .PEVMF͕ඞཁʹͳΓ·͢ɻ w
·ͨɺ͜ͷྫͰ1SFTFOUFSͷґଘؔղܾ͢ Δඞཁ͕͋Γ·͢ɻ w ͜ΕΛ౿·͑ͯ࣍ͷϖʔδͰ.PEVMFΛ࡞͠ ·͢ɻ
w Ϣʔεέʔεͷ.PEVMFΛJNQPSUͯ͠ɺ $POUSPMMFSͷίϯετϥΫλ%*͍ͯ͠·͢ɻ w DPOUSPMMFSTʹίϯτϩʔϥʔͷࢦఆΛ͍ͯ͠· ͢ɻ w 1SFTFOUFSΫϥεΛQSPWJEFSTʹࢦఆ͍͠·͢ɻ w <ิ>͜͜ͰϢʔεέʔεͷ*'ʹґଘ͍ͯ͠·
͕͢ɺϢʔεέʔεͷ*'ΛΒͣʹ۩Ϋϥεͷ ࢦఆͰ͋Γ·ͤΜɻ w *'ʹґଘ͍ͤͯ͞Δͷ$POUSPMMFSͷςελ ϏϦςΟΛ্ͤ͞ΔͨΊͰ͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS @Module( { imports: [UseCaseModule] , controllers: [CatController] , providers: [CatPresenter] , } ) export class AdaptorWebApiModule { }
w ࠷ऴతʹ"QQ.PEVMFͰࠓ·Ͱ࡞ͨ͠.PEVMF ΛJNQPSU͠·͢ w ηΧϯμϦʔΞμϓλ6TF$BTF.PEVMFͰ JNQPSU͞Ε͍ͯΔͨΊ͜͜ͰෆཁͰ͢ɻ w "QQ.PEVMFΛ/FTU'BDUPSZDSFBUFʹͯ͠ Ͱ͢ɻ ϨΠϠʔڥքΛߏ͢Δ
"QQ.PEVMF @Module( { imports: [UseCaseModule, AdaptorWebApiModule] , } ) export class AppModule { } export async function main() { const app = await NestFactory.create(AppModule) ; await app.listen(80, '0.0.0.0') ; }
࠷ޙʹ
࠷ޙʹ w ΫϦʔϯͳϨΠϠʔڥքΛ࡞ΔͨΊʹɺґଘؔٯసͷݪଇΛ׆༻͠ґଘؔΛೖ͠·͢ɻ w %*ίϯςφΛ͏ͱɺ࣮ͱઃఆΛ͚ͯґଘؔͷઢ͕Ͱ͖·͢ɻ w /FTU+4ͷ.PEVMFTΛ͑ґଘؔͷೖͷׂ౷࣏͕ՄೳͰ͢ɻ w ࠓճϨΠϠʔผʹઢͷׂ౷࣏Λ͠·ͨ͠ɻ w
αϯϓϧίʔυҎԼ w IUUQTHJUIVCDPNLJNVUZBNOFTUKTDMFBOBSDIJUFDUVSFUSFF ·ͱΊ
࠷ޙʹ w Έํͷߟ͑ํಉ͡Ͱ͕͢ɺ͜͜Ͱઆ໌ͨ͠ͷύλʔϯͰ͢ɻ w ϓϩδΣΫτͷঢ়گϓϩμΫτͷಛʹΑͬͯͲ͏͍͏ߏʹ͢Δ͔ݕ౼͠·͠ΐ͏ɻ w ͨͩ͠ɺߏΛΉ্Ͱͷߟ͑ํಉ͡Ͱ͢ɻ w lΞʔΩςΫνϟͷϧʔϧͲΕಉ͡Ͱ͋Δʂz˞ ҙॻ͖
˞3PCFSU$.BSUJO ʰ$MFBO"SDIJUFDUVSFୡਓʹֶͿιϑτΣΞͷߏͱઃܭʱʮংจʯΑΓ
࠷ޙʹ 8FBSF)JSJOH w ΤϯδχΞʹؔͯ͠ଟ͘ͷٻਓ͕͍͟͝·͢ɻ˞ w όοΫΤϯυʹؔͯ͠5ZQF4DSJQUΛओཁݴޠͱ ͨ͠ืू͋Γ·͢ɻ˞ w 8FCͷϑϩϯτΤϯυ5ZQF4DSJQUΛར༻͍ͯ͠ ·͢ɻ˞
IUUQTIFSQDBSFFSTWLBLFIBTIJ ˞ొஃ࣌ͰͷٻਓใͰ͢ɻ