Look up service implementations dynamically

允我心安 提交于 2020-05-28 04:48:44

问题


Our Angular application has a service which can have different implementations, aka. “strategies”. For simplicity, let’s assume it’s an “event reporting” service. The event reporting service has a function for reporting information. Depending on a runtime preference, the reporting can either turned off, go to the console, or be sent to a REST API, or go somewhere else.

Using pure TS, this would look like:

interface IReporter {
  report (message: string): void;
}

class NoReporter implements IReporter {
  report (message: string): void {
    // no op.
  }
}

class ConsoleReporter implements IReporter {
  report (message: string): void {
    console.log(message);
  }
}

// etc.

In a consumer, I’d put some factory which delivers the desired reporter, e.g. based on a user-preference setting:

getReporter (key: string): IReporter {
  switch (key) {
    // … tedious cases, which need to be mainted. Yikes!
  }
}

However, this feels not very “Angular”-like. First step would probably be to make proper Angular services of the individual reporters, but this alone feels like little gained. So: Is there some existing mechanism which would give me above factory functionality to dynamically look up an implementation? Any patterns, example or best practices to follow?


回答1:


Like mentioned in the comment FactoryProviders perfectly solve this problem.

You have to define your IReporter interface as an class interface because interfaces don't exist at runtime and therefore they are no valid DI tokens:

export abstract class IReporter {
  report: (message: string) => void;
}

@Injectable()
export class NoReporter implements IReporter{
  report(message:string):void{

  }
}

@Injectable()
export class ConsoleReporter implements IReporter {
  report(message: string): void {
    console.log(message);
  }
}

Now you could create your reporterFactory and reporterProvider like shown below:

const reporterFactory = (key: string) => {
  switch (key) {
    case 'no-report':
      return () => new NoReporter();
    case 'console-report':
      return () => new ConsoleReporter();
    default:
      return () => new ConsoleReporter();
  }
};

export const reporterProvider = (key: string) => {
  return {
    provide: IReporter,
    useFactory: reporterFactory(key)
  }
};

And inject a reporter in your component:

@Component({
  selector: 'test',
  template: `TESTCOMPONENT`,
  providers: [
    reporterProvider('console-report')
  ]
})
export class TestComponent {
  constructor(private reporter: IReporter) {
    reporter.report('it works!!!');
  }

}


来源:https://stackoverflow.com/questions/60298855/look-up-service-implementations-dynamically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!