【问题标题】:Binding a class to an interface将类绑定到接口
【发布时间】:2015-11-22 03:57:43
【问题描述】:

使用打字稿,我可以轻松地将类绑定到自己:

bootstrap(MyAppComponent, [MyClass]);

但是,我想将我的类绑定到一个接口,如下所示:

boostrap(MyAppComponent, [???]);

这样我就可以按如下方式注入它:

class MyAppComponent {
    constructor(my_class : IMyClass){
    }
};

这在 Angular2 中可行吗?如果是,我必须如何指定绑定?

【问题讨论】:

    标签: dependency-injection typescript angular


    【解决方案1】:

    简而言之,问题是编译打字稿时接口消失了。所以你必须使用带有字符串的@Inject。

    或者还有其他选择,如果你检查the last article of Victor Savkin 你可以在 cmets 中找到这个:

    一些背景。在 TypeScript 中,接口是结构化的,不会在运行时保留。所以你必须按如下方式使用 ILoginService:

    constructor(@Inject("ILoginService") s:ILoginService).
    

    您不必使用字符串 - 可以在其中传递任何对象。我们实际上提供了一个名为 OpaqueToken 的对象,可以用于此目的。

    interface ILoginService { login(credentials);}
    const ILoginService = new OpaqueToken("LoginService");
    

    可以这样使用:

    constructor(@Inject(ILoginService) s:ILoginService).
    

    【讨论】:

    • 为什么 new OpaqueToken("LoginService") 被通过 LoginService 而不是 ILoginService
    • @DannyBullis 它没有传递 LoginService 用于使用,这里所做的是我们创建一个 OpaqueToken 并传递一个我们想要稍后在构造函数中请求 OpaqueToken 时使用的值。这只是一个示例字符串。请注意,不推荐使用 OpaqueToken,应使用 InjectionToken。更多了解可以在这里找到stackoverflow.com/questions/41289264/…
    【解决方案2】:

    我不知道接口是否可能,因为接口在运行时不可用(javascript 不知道接口)。 但是可以使用抽象类来完成。

    //abstract-parent-service.ts

    export class DatabaseService{
        getService: ()=>string;
    }
    

    //hibernate.service.ts

    import {DatabaseService} from "./abstract-parent-service";
    
    export class HibernateService implements DatabaseService{
      constructor() { }
      getService() {
        return "i am hibernate";
      }
    }
    

    //jdbc.service.ts

    import {DatabaseService} from "./abstract-parent-service";
    
    export class JDBCService implements DatabaseService{
      constructor() { }
      getService() {
        return "i am Jdbc";
      }
    }
    

    //cmp-a.component.ts

    import {DatabaseService} from "./abstract-parent-service";
    import {HibernateService} from "./hibernate.service";
    
    @Component({
        selector: 'cmp-a',
        template: `<h1>Hello Hibernate</h1>`,
        providers: [{provide: DatabaseService, useClass: HibernateService}]
    })
    export class CmpAComponent {
        constructor (private databaseService: DatabaseService) {
            console.log("Database implementation in CompA :"+this.databaseService.getService());
        }
    }
    

    //cmp-b.component.ts

    import {DatabaseService} from "./abstract-parent-service";
    import {HibernateService} from "./hibernate.service";
    
    @Component({
        selector: 'cmp-b',
        template: `<h1>Hello Jdbc</h1>`,
        providers: [{provide: DatabaseService, useClass: JDBCService}]
    })
    export class CmpAComponent {
        constructor (private databaseService: DatabaseService) {
            console.log("Database implementation in CompA :"+this.databaseService.getService());
        }
    }
    

    但是这个实现的问题是 HibernateService 和 JDBCService 现在不能扩展任何其他类,因为它们 已经和DatabaseService结婚了。

    class A{
        constructor(){
            console.log("in A");
        }
    }
    class B extends A{
        constructor(){
            super();
            console.log("in B");
        }
    }
    class C extends A{
        constructor(){
            super();
            console.log("in C");
        }
    }
    let c = new C();
    
    //This thing is not possible in typescript
    class D extends B, C{//error:  Classes can only extend a single class
        constructor(){
            super();// which constructor B or C
            console.log("in D");
        }
    }
    

    如果您将此模式用于 DI,请确保您的子类服务将来不会扩展任何其他功能。

    【讨论】:

      猜你喜欢
      • 2014-08-23
      • 1970-01-01
      • 2017-01-29
      • 2022-09-10
      • 2016-10-23
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多