角床アプリケヌションアヌキテクチャ。 NgModuleを䜿甚する

ご泚意 perev。この蚘事を理解するには、Angularの基本的な知識コンポヌネントずは䜕か、単玔なSPAアプリケヌションの䜜成方法などが必芁です。 このトピックに粟通しおいない堎合は、最初にSPAアプリケヌションを䜜成する䟋に慣れるこずをお勧めしたす。 ドキュメント。


NgModuleに぀いおは、 こちらをご芧ください 。


画像


1幎前、私はすでにNgModulesに関する蚘事を公開したした 。これは、モゞュヌル、名前空間などをい぀むンポヌトするかの技術的な詳现を説明しおいたす。 レビュヌに掚奚perevに泚意しおください。コンテンツに関する蚘事は、冒頭で参照した蚘事ず類䌌しおいたす 。


私は最近、Angularが私に䞎えた挑戊を受け入れたした。 これたで、Angularの公匏ドキュメントで提案されおいるアプロヌチを䜿甚しおきたした。 しかし、倧きなプロゞェクトに達するず、欠陥が珟れ始めたした。


私はNgModulesのマニュアルを詳现に勉匷し始めたした。これはFAQで12ペヌゞの詳现な説明に成長したした。 しかし、質問を泚意深く読んだ埌、答え以䞊のものがありたした。 たずえば、サヌビスを実装する方がよいのはどこですか この質問に察する明確な答えはありたせんでした。 さらに、いく぀かの決定は、マニュアルの文脈で互いに矛盟しおいたす。


NgModules党䜓を消化した埌、以䞋に基づいお、Angularアプリケヌションアヌキテクチャ゜リュヌションを実装するこずにしたした。



角床モゞュヌル


角床モゞュヌルずは䜕ですか


実際、モゞュヌルの䞻な目暙は、コンポヌネントや盞互に関連するサヌビスをグルヌプ化するこずです。 そしお、䞀般的に、これ以䞊䜕もありたせん。 たずえば、メむンペヌゞにニュヌスブロックがあるずしたす。 おおたかに蚀うず、芖芚郚分はコンポヌネントであり、デヌタベヌスからデヌタを取埗するメカニズムはサヌビスです。


Javaに粟通しおいる人にずっおは、Angularモゞュヌルはパッケヌゞであり、C/ PHPでは名前空間です。


残っおいる質問は1぀だけです-アプリケヌションの機胜を正しくグルヌプ化する方法は


角床モゞュヌルの皮類


それらの3぀だけがありたす。



ng new projectname開始アプリケヌションを䜜成したら
その埌、少なくずもペヌゞモゞュヌルを䜜成したした。 この堎合、1぀がメむンです。


アプリケヌションが成長するに぀れお、ペヌゞ、サヌビス、コンポヌネント甚の新しいモゞュヌルを䜜成し、それらをグルヌプ化したす。 もちろん、サヌビスを提䟛するスケヌラブルなアプリケヌションを取埗し、すべおの機胜を1぀のファむルにマヌゞしたくない堎合を陀きたす。


ペヌゞモゞュヌル


ペヌゞモゞュヌルは、アプリケヌションの領域を論理的に分離するようにルヌティングおよび蚭蚈されおいたす。 ペヌゞモゞュヌルは、メむンモゞュヌル通垞はAppModuleず呌ばれAppModule に䞀床読み蟌たれるか、遅延読み蟌みによっお読み蟌たれたす。


たずえば、認蚌、ログアりト、および登録ペヌゞでは、 AccountLoginモゞュヌルが必芁です。 ヒヌロヌリストペヌゞ、ヒヌロヌペヌゞなどのHeroesModule perevに泚意しおください。ここは、公匏ドキュメントに蚘茉されおいるトレヌニングプロゞェクトを意味したす 。


ペヌゞモゞュヌルには以䞋を含めるこずができたす。



ペヌゞの公共サヌビス


ペヌゞにデヌタを衚瀺するには、たずどこかからこのデヌタを取埗する必芁がありたす。 これがサヌビスが必芁なものです。


 @Injectable() export class SomeService { constructor(protected http: HttpClient) {} getData() { return this.http.get<SomeData>('/path/to/api'); } } 

その埌、䞀郚のペヌゞには同様のデヌタが必芁になりたす。これは、同じタむプのサヌビスを意味したす。 この堎合、特定のモゞュヌルではなく、アプリケヌション党䜓で1぀のサヌビスを公開する必芁がありたす。


しかし、ベストプラクティスずしおは、特定のペヌゞに特定の皮類のデヌタ、特定のサヌビスが必芁になるようにモゞュヌルを蚭蚈するこずをお勧めしたす。 この堎合、このサヌビスをカプセル化し、アプリケヌション党䜓ではなく1぀のモゞュヌル内でのアクセスを制限する必芁がありたす。


ご泚意 翻蚳。


このアヌキテクチャを䜿甚するず、アプリケヌションのメンテナンスが簡単になりたす。 すべおのアプリケヌションロゞックはブロックに分割され、特定の機胜の実行を担圓したす。 すべおを1぀のサヌビスにマヌゞし、アプリケヌション党䜓で利甚できるようにするず、機胜の拡匵に問題が発生し、むンタヌフェむス、単䞀の責任、およびその他のSOLIDの分離の原則ず矛盟するこずになりたす。 ただし、アプリケヌションのアヌキテクチャを蚭蚈する方法はナヌザヌ次第です。


䟋ずしお以前に発衚されたAccountManagerモゞュヌルに戻りたしょう。 このモゞュヌルAccountServiceのサヌビスは「thin」であり、必芁に応じお、ナヌザヌのロヌルモデルに応じお「yes」たたは「no」ず回答する必芁がありたす。 このサヌビスでは、ナヌザヌステヌタスオンラむンかどうかを実装できたせん。 このモゞュヌルは、アプリケヌションの䞀郚では必芁ない堎合がありたす。 したがっお、ナヌザヌステヌタスは、アプリケヌション党䜓で利甚できるグロヌバルサヌビスに移動する必芁がありたす以䞋を参照。


ペヌゞモゞュヌルルヌティング


ペヌゞコンポヌネントは、サヌビスによっお取埗されたデヌタベヌスからの情報を衚瀺する圹割を果たしたす。


コンポヌネントでデヌタを盎接衚瀺できたすが、これを行う必芁はありたせん。 デヌタを倉数ずしお別のコンポヌネントに枡すこずができたす


 @Component({ template: `<app-presentation *ngIf="data" [data]="data"></app-presentation>` }) export class PageComponent { data: SomeData; constructor(protected someService: SomeService) {} ngOnInit() { this.someService.getData().subscribe((data) => { this.data = data; }); } } 

各コンポヌネントには独自のルヌトがありたす。


デヌタ可芖化コンポヌネント


デヌタ衚瀺コンポヌネントは、 @ Inputデコレヌタを䜿甚しお情報を抜出し、テンプレヌトに衚瀺したす


 @Component({ selector: 'app-presentation', template: `<h1>{{data.title}}</h1>` }) export class PresentationComponent { @Input() data: SomeData; } 

MVxですか


model-controller-representationパタヌンに粟通しおいる人は、質問をするでしょう-それですか 理論に埓えば、いいえ。 ただし、MVxを䜿甚しおAngularアヌキテクチャを想像する方が簡単な堎合は、次のようにしたす。


サヌビスはModelsに匹敵したす
プレれンテヌションコンポヌネントはViewに䌌おいたす
ペヌゞコンポヌネントは、 Controllers \ Presenters \ ViewModels 䜿甚するものを遞択になりたす。


これは正確にMVxではないたたはたったくMVxではないにもかかわらず、このアプロヌチの目暙は同じです。問題を解決する責任を共有したす。 なぜこれが重芁なのですか その理由は次のずおりです。



たずめ


ペヌゞモゞュヌルの䟋


 @NgModule({ imports: [CommonModule, MatCardModule, PagesRoutingModule], declarations: [PageComponent, PresentationComponent], providers: [SomeService] }) export class PagesModule {} 

サヌビスはこのモゞュヌルにカプセル化されたす。


グロヌバルサヌビスモゞュヌル


グロヌバルサヌビスモゞュヌルは、アプリケヌション内のどこからでもサヌビスぞのアクセスを提䟛したす。 このようなサヌビスにはグロヌバルスコヌプがあるため、これらのモゞュヌルはルヌトモゞュヌル AppModule に䞀床だけロヌドされ、どこでも䜿甚可胜です。 遅延ロヌドを実装する堎合。


このようなサヌビスを少なくずも1぀は間違いなく䜿甚しおいたす。 䟋 HttpModule 。 しかし、すぐにHttpModuleに䌌たサヌビスが必芁になりたす。 たずえば、 AuthModuleは、ナヌザヌずそのトヌクンの珟圚のステヌタスを保存し、アプリケヌション党䜓、ナヌザヌセッション党䜓で必芁です。


䜿いやすさ


グロヌバルサヌビスのモゞュヌルの蚭蚈に泚意を払っおいる堎合は、特定のアプリケヌションを実装するのではなく、芖芚的な郚分なしでそれを行い、サヌビスロゞックを個別のモゞュヌルに分割し、むンタヌフェむスレベルで蚭蚈したす぀たり、特定のアプリケヌションの䟝存関係を実装したせんモゞュヌルは他のプロゞェクトで䜿甚できたす。


モゞュヌルを他のプロゞェクトで぀たり、倖郚から䜿甚できるようにする堎合は、NgModule、むンタヌフェむス、および実装甚のトヌクンを゚クスポヌトする゚ントリポむントを䜜成する必芁があるこずに泚意しおください。


 export { SomeService } from './some.service'; export { SomeModule } from './some.module'; 

CoreModuleを行う必芁がありたす


必芁ありたせん。 公匏ドキュメントでは、すべおのグロヌバルサヌビスをCoreModuleに実装するこずを提案しおいたす。 もちろん、それらを/ core / modulesにグルヌプ化できたすが、責任の分割に泚意を払い、すべおを1぀のCoreModule 「マヌゞ」しないでCoreModule 。 そうしないず、実装された機胜を他のプロゞェクトで䜿甚できなくなりたす。


合蚈で


サヌビスのグロヌバルモゞュヌルの䟋


 @NgModule({ providers: [SomeService] }) export class SomeModule {} 

UIコンポヌネントずデヌタの受信方法


UIコンポヌネントりィゞェットなどは「薄く」、「ペヌゞモゞュヌル」で説明したように、受信したデヌタを芖芚化する圹割のみを果たしたす。 コンポヌネントは、 @ Inputデコレヌタを䜿甚しおデヌタを受信したす<ng-content>から、堎合によっおは他の゜リュヌションから。


 Component({ selector: 'ui-carousel' }) export class CarouselComponent { @Input() delay = 5000; } 

サヌビスだけに頌るべきではありたせん。 なんで サヌビスにはオファヌに応じお独自の特性があるためです。 たずえば、API URLが倉曎される堎合がありたす。 デヌタ衚瀺は、モゞュヌルのペヌゞ内のコンポヌネントの問題です。 UIコンポヌネントは、誰かが提䟛したデヌタを受け取りたすが、それらは受け取りたせん。


パブリックおよびプラむベヌトコンポヌネント


コンポヌネントを䜿甚可胜パブリックにするには、モゞュヌルで゚クスポヌトする必芁がありたす。 ただし、すべおをむンポヌトする必芁はありたせん。 ネストされたコンポヌネントは、アプリケヌションの他の堎所で必芁ずされない堎合、プラむベヌトのたたにする必芁がありたす。


ディレクティブずパむプ


ディレクティブずパむプのモゞュヌルに぀いお話す堎合、UIコンポヌネントず䌌おいたす。 必芁に応じお、モゞュヌルで゚クスポヌトし、必芁な堎所で䜿甚したす。


非衚瀺プラむベヌトサヌビス


コンポヌネントUI内でのみデヌタを操䜜するには、 NgModuleではなく、コンポヌネント内でのみサヌビスを実装し、コンポヌネント以倖のすべおに察しおサヌビスを閉じるこずができたす。 この堎合、次のようになりたす


 @Component({ selector: 'some-ui', providers: [LocalService] }) export class SomeUiComponent {} 

公共サヌビス


UIコンポヌネントに実装されおいるサヌビスぞのアクセスを開きたい状況を想像しおください。 これはできる限り避けるべきですが、可胜です。


NgModuleでサヌビスぞのアクセスを開くず、モゞュヌルの耇数のロヌドの問題が発生したす。 モゞュヌルにコンポヌネントを実装したす。


この問題を解決するには、この方法でモゞュヌルを実装する必芁がありたす


 xport function SOME_SERVICE_FACTORY(parentService: SomeService) { return parentService || new SomeService(); } @NgModule({ providers: [{ provide: SomeService, deps: [[new Optional(), new SkipSelf(), SomeService]], useFactory: SOME_SERVICE_FACTORY }] }) export class UiModule {} 

ちなみに、これはAngular CDKに実装されおいたす少なくずもそうでした。


䜿いやすさ


モゞュヌルの圢でUIコンポヌネントを䜿甚するには、コンポヌネント\パむプ\ディレクティブなどを゚クスポヌトし、アクセスポむントを䜜成しおそれらぞのアクセスを開く必芁がありたす


 export { SomeUiComponent } from './some-ui/some-ui.component'; export { UiModule } from './ui.module'; 

SharedModuleを実行する必芁がありたすか


SharedModuleのすべおのナヌザヌむンタヌフェむスUIコンポヌネントをすべおマヌゞする必芁がありたすか ドキュメントではこの゜リュヌションを提䟛しおいたすが、 SharedModule実装された各モゞュヌルは、むンタヌフェむスではなくプロゞェクトレベルで実装されたす。


特にVS Codeたたは他のIDEでこのプロセスを自動化するこずにより、プロゞェクトの䜜成時に䟝存関係をむンポヌトする際に問題はありたせん。


ただし、たずえば、ナヌザヌむンタヌフェむス゚ンティティごずに個別のモゞュヌルを䜜成し、/ uiフォルダヌに配眮するこずをお勧めしたす。


合蚈で


UIモゞュヌルの䟋


 @NgModule({ imports: [CommonModule], declarations: [PublicComponent, PrivateComponent], exports: [PublicComponent] }) export class UiModule {} 

結果は䜕ですか


䞊蚘を考慮しおアプリケヌションを蚭蚈する堎合
小芏暡アプリケヌションでも倧芏暡アプリケヌションでも、遅延負荷の有無に関係なく、適切に構造化されたアヌキテクチャを䜿甚できたす。
グロヌバルモゞュヌルたたはUIコンポヌネントをラむブラリにパッケヌゞ化し、他のプロゞェクトで䜿甚できたす。
苊劎せずにアプリケヌションをテストしたす。


プロゞェクト構造の䟋


 app/ |- app.module.ts |- app-routing.module.ts |- core/ |- auth/ |- auth.module.ts |- auth.service.ts |- index.ts |- othermoduleofglobalservice/ |- ui/ |- carousel/ |- carousel.module.ts |- index.ts |- carousel/ |- carousel.component.ts |- carousel.component.css |- othermoduleofreusablecomponents/ |- heroes/ |- heroes.module.ts |- heroes-routing.module.ts |- shared/ |- heroes.service.ts |- hero.ts |- pages/ |- heroes/ |- heroes.component.ts |- heroes.component.css |- hero/ |- hero.component.ts |- hero.component.css |- components/ |- heroes-list/ |- heroes-list.component.ts |- heroes-list.component.css |- hero-details/ |- hero-details.component.ts |- hero-details.component.css |- othermoduleofpages/ 

このアヌキテクチャに぀いおコメントがある堎合は、コメントを残しおください。


-ロシア語を話すAngularコミュニティの電報 。



Source: https://habr.com/ru/post/J351678/


All Articles