最佳实践:具有不同服务的通用组件

时间:2018-06-17 16:31:27

标签: angular2-services generic-programming angular2-components

我们说我们有一个TableComponent。 TableComponent的目的是显示超级英雄并删除/添加它们。为此,它使用HeroService。

TableComponent {
  constructor() {
    heroService: HeroService
  }
  getList() {
    this.heroService.getHeroes().subscribe(...)
  }
  addCharacter(character: Character) {
    this.heroService.postHero(character).subscribe(...)
  }
  removeCharacter(character: Character) {
    this.heroService.deleteHero(character).subscribe(...)
  }
}

现在我们想为我们的超级恶棍使用相同的TableComponent。 villainService已经存在并且可以使用了。超级英雄和超级恶棍也分享了尽管他们在同一个阶层的分歧。唯一不同的是他们的服务。实施它的最简洁方法是什么?

我的第一个想法是扩展两个服务:

tableOptions {
  getList: this.getHeroes,
  addObject: this.postHero,
  deleteObject: this.deleteHero
}

并修改组件,如:

TableComponent {
  Input() service; // HeroService or VillainService

  getList() {
    this.service.tableOptions.getList.subscribe(...)
  }
  addCharacter(character: Character) {
    this.service.tableOptions.addObject(character).subscribe(...)
  }
  removeCharacter(character: Character) {
    this.service.tableOptions.deleteObject(character).subscribe(...)
  }
}

但我希望有一些可能更清洁的最佳实践技巧。提前谢谢!

1 个答案:

答案 0 :(得分:1)

此处的最佳做法是将具有显示层的组件与具有服务层的容器分开。所以你的表组件应该只发出表格上发生的事情的信息,如:

TableComponent {
  @Input() data;
  @Output() addCharacterClicked = new EventEmitter();
  @Output() removeCharacterClicked = new EventEmitter();

  addCharacter(character: Character) {
     this.addCharacterClicked.emit(character);
  }

  removeCharacter(character: Character) {
     this.removeCharacterClicked.emit(character);
  }
}

例如,如果你想在一个表中显示heros和villain,那么你可以在容器层中使用这个组件:

@Component({
   template: `<app-table-component 
                [data]="characters" 
                (removeCharacterClicked)="onRemoveCharacterClicked($event)">
              </app-table-component>`
}
export class CharactersTableContainer {
   characters: Character[] = [];

   constructor(private heroService: HeroService, 
               private villainService: VilliansService) { }

   ngOnInit() {
     this.heroService.getHeroes().subscribe(heros => this.characters = this.characters.concat(heros));
     this.villainService.getVillians().subscribe(villains => this.characters = this.characters.concat(villains));
   }

   // similiar method to add character
   onRemoveCharacterClicked(character: Character) {
     if (character instacnceof Hero) {
       this.heroService.removeHero(character).subscribe(response => {
       // when backend reponds without error remove character from local list
         this.removeCharacter(character);
       });
     } else {
       this.villainService.removeVillian(character).subscribe(response => {
         this.removeCharacter(character);
       });
     }  
   }

   private removeCharacter(character: Character) {
     // implement method for removing item from this.characters list
   }
 }

多亏了这一点,你可以轻松地更改容器和表组件中的逻辑,而不需要知道数据会发生什么。表组件应该只发出事件,并不关心它们发生了什么。将服务传递给组件并不是一个好主意。请记住始终单独的服务层(容器)和组件层(仅接受输入并在输出上发出事件)