Angular6中组件之间共享逻辑时如何使用组合而不是继承?

How to use composition instead of inheritance when sharing logic between components in Angular 6?

我在 Angular 中有一个结构如下的模块:

moduleName
    componentA
    componentB

现在 componentAcomponentB 非常相似,因为它们共享一些属性和方法,例如:

protected available: boolean = true;

由于不想重复,我创建了一个基础 class,它存储了所有这些:

export abstract class BaseComponent {
    protected available: boolean = true;
}

并且两个控制器都继承自 class:

import { BaseComponent } from '../base.component';

export class ComponentA extends BaseComponent implements OnInit {
    constructor() {
        super();
    }

    ngOnInit() {
        console.log(this.available);
    }
}

这很好用。然而,当我研究这个灵魂时,很多人都在说:

Don't use inheritance, use composition in this case.

好的,但是我怎样才能使用组合呢?与当前解决方案相比,收益真的那么大吗?

非常感谢您的宝贵时间。

要在 angular 中组合对象,您需要在 class 中引用该对象,它共享数据和功能。为此,您需要使用 Angular 服务,并将它们注入您的 class,并且每个组件应该有 1 个服务实例。

  1. 通过 运行 创建新服务 ng g s my-service,从您的服务注释中删除 providedIn: 'root'(我们希望为每个组件提供实例)
  2. 添加public available: boolean = true;到服务
  3. provide 通过组件的服务,在组件的 @Component 配置中
  4. 在你的两个组件构造函数中注入服务,constructor(private myService:MyService)

现在您有了一个保留数据和功能的组合

@Component({
  selector: 'app',
  templateUrl: './app.my-component.html',
  styleUrls: ['./app.my-component.css'],
  providers: [MyService]
})
export class MyComponent {
  constructor(private myService: MyService) {
  }
}

如果您使用大部分相同的逻辑创建相同的组件。您可以使用继承,例如 controlSelectComponent 和 controlInputComponent stackblitz example

对于组合,您需要创建服务并将其提供给两个组件。但是因为all service are singletone,你不保持服务中的组件状态。当一个组件改变状态时,另一个组件崩溃。

您也可以在提供者部分为每个组件提供服务

@Component({
  selector: 'app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [MyService]
})
export class AppComponent {
  constructor(private myService: MyService) {
  }
}

但是如果在服务中保存状态不是最好的解决方案

结论

使用服务和组合在组件之间共享辅助方法。

对具有相同逻辑和状态变化的组件使用抽象 class 和继承。

我还建议您阅读有关组合优于继承的内容。 Angular 使用的语法 (InversifyJs) 非常相似。请看这个blog