Наша команда в настоящее время пробует архитектуру Angular, и я тоже хочу получить советы от других людей.
"Базовая" архитектура Angular будет выглядеть примерно так
Angular Architecture
Компонент имеет представление, его логику и его зависимости.
Но мы хотим сделать более надежный подход, который говорит: «У класса, функции или метода должна быть только одна ответственность». Поэтому мы подумали, что можем позволить классу компонента управлять только представлением и экспортировать его логику в сильно связанный сервис. Наша архитектура теперь выглядит примерно так:
Наша угловая архитектура
Но что-то странное в использовании сильно связанного сервиса для экспорта логики компонента, мы обсуждали этов нашей команде принцип Angular сервиса должен заключаться в выполнении бизнес-логики, такой как вызов API, и должен использоваться в любом месте, не сильно связан с чем-то вроде компонента.
Так вот почему я здесь, мыХотели бы получить советы от сообщества разработчиков о нашей архитектуре и быть уверенными, что мы не движемся в нестабильном / неправильном направлении (пожалуйста, сообщите нам, если вы так думаете и почему)
Вот пример того, что мыdid
У нас есть компонент, который должен отображать список продуктов. Мы экспортировали логику в две службы:
- ProductListItemService , которые управляют элементом списка
- ProductsListService , которые управляют самим списком
Вы можете себе представить, что это будет трудно использовать в другом месте, если нам не нужен тот же список в другом представлении
Мы использовали инверсию управления из SOLID и внедрили наши сервисы с TokenInjection, котороепозволяет нам использовать интерфейсы
Компонент абсолютно ничего не делает, кроме вызова своих логических служб и обработки представления (показать загрузчик, изменить переменную). Здесь вы идете с кодом
// IMPORTS ARE HERE
@Component({
selector: 'app-products-list',
templateUrl: './products-list.component.html',
styleUrls: ['./products-list.component.css'],
providers: [{
provide: BASE_PRODUCT_LIST_ITEM_SERVICE_TOKEN, // This is a token used to allows us to inject an interface
useClass: ProductListItemService,
},
{
provide: PRODUCTS_LIST_SERVICE_TOKEN, // This is a token used to allows us to inject an interface
useClass: ProductsListService,
},
{
provide: MODAL_SERVICE_TOKEN, // This is a token used to allows us to inject an interface
useClass: ModalService
},
]
})
export class ProductsListComponent implements OnInit {
// CLASS MEMBERS ARE HERE
constructor(
@Inject(BASE_APP_CONFIG_PROVIDER_TOKEN) private appConfig: BaseAppConfigProvider,
@Inject(BASE_PRODUCT_LIST_ITEM_SERVICE_TOKEN) private _productListItemService: BaseProductListItemService,
@Inject(BASE_PRODUCTS_LIST_SERVICE_TOKEN) private _productsListService: BaseProductsListService
) {
}
async ngOnInit() {
await this.initProducts();
// Subscribe on a promise from the service that manage the rows
// When the service upsert a row, it notify that and the component can perform action(s)
this._productListItemService.onUpdated.subscribe(async () => {
await this.initProducts();
});
}
/**
* Get the list of TD products linked to the btob account
**/
public async initProducts() {
this.loading = true;
// Call the service that manage the list to populate the view
this.products = await this._productsListService.loadProducts(this.btobAccount.Id);
this.loading = false;
}
/**
* Open a dialog to confirm the activation or deactivation of a product
* @param event
* @param productId
* @param newStatus
*/
public openUpdateProductStatusModal(event: MouseEvent, productId: number, newStatus: boolean) {
// Call service that manage the rows
this._productListItemService.openUpdateStatusModal(event, this.products, productId, newStatus);
}
/**
* Open the product modal
* @param state The state to open the modal in. Either insert or update
* @param product The product to update if the state is update
*/
public openProductModal(state: Crud, product?: Product) {
// Call service that manage the rows
this._productListItemService.openUpsertModal(state, this.btobAccount.Id, product);
}
/**
* Open the product params modal
* @param product
*/
public openProductParamsModal(product?: Product): void {
// Call service that manage the rows
this._productListItemService.openProductParamsModal(product);
}
/**
* Check if a product is expired
* @param product The product to check
*/
public isExpiredProduct(product: Product): boolean {
// Call service that manage the rows
return this._productListItemService.isExpired(product);
}
public openCommentModal(id: number, name: string, comment: string): void {
// Call service that manage the rows
this._productListItemService.openUpdateCommentModal(id, name, comment);
}
}