我不明白何时使用@Inject以及何时使用@Injectable?
import {Component, Inject, provide} from '@angular/core';
import {Hamburger} from '../services/hamburger';
export class App {
bunType: string;
constructor(@Inject(Hamburger) h) {
this.bunType = h.bun.type;
}
}
Run Code Online (Sandbox Code Playgroud)
和..
import {Injectable} from '@angular/core';
import {Bun} from './bun';
@Injectable()
export class Hamburger {
constructor(public bun: Bun) {
}
}
Run Code Online (Sandbox Code Playgroud) 从您在AppModule中提供服务的Angular 5到Angular 6的更改,您在@Injectable装饰器中设置'provideIn'键我已经更改了所有服务以使用新的"provideIn"方法.但是,异常是我的拦截服务.
如何为'root'提供HTTP_INTERCEPTORS标记并使用InterceptorService?
这是我使用atm的Angular 5方式:
@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}
Run Code Online (Sandbox Code Playgroud)
在AppModule中:
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorService,
multi: true
}]
Run Code Online (Sandbox Code Playgroud)
但Angular 6的方式是什么?
我尝试过类似的东西
@Injectable({
provideIn: 'root',
useValue: HTTP_INTERCEPTORS,
deps: [forwardRef(() => InterceptorService)]
})
export class InterceptorService implements HttpInterceptor {
...
}
Run Code Online (Sandbox Code Playgroud)
还有很多其他的Injectable变种,但似乎无法弄清楚如何在不将对象文字直接写入模块的提供者的情况下使其工作.
我试图对角度服务进行单元测试时遇到问题.我想验证此服务是否正确调用注入其中的另一个服务.
假设我有这个注入ServiceInjected的ServiceToTest:
ServiceToTest .service.ts
@Injectable()
export class ServiceToTest {
constructor(private _si: ServiceInjected) {}
public init() {
this._si.configure();
}
}
Run Code Online (Sandbox Code Playgroud)
ServiceInjected.service.ts
@Injectable()
export class ServiceInjected {
constructor() {}
public configure() {
/*Some actions*/
}
}
Run Code Online (Sandbox Code Playgroud)
有了这些服务,现在我编写单元测试:
const serviceInjectedStub = {
configure(): void {}
}
describe('ServiceToTest service Test', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ServiceToTest ,
{ provide: ServiceInjected, useValue: serviceInjectedStub }]
});
});
it('should be initialize the service injected', inject([ServiceToTest],
(tService: ServiceToTest) => {
spyOn(serviceInjectedStub, 'configure');
tService.init();
expect(serviceInjectedStub.configure).toHaveBeenCalled();
})); …
Run Code Online (Sandbox Code Playgroud)从 lib(dev) 代码中初始化的 getIt 获取实例是否可以,或者我应该使用其他方式或其他 DI 设置进行测试?
请参考下面的代码:
void main() {
TravellerProfileViewModel travellerProfileViewModel;
UserService mockUserService;
setUpAll(() {
// CoreInjector is initialised in lib, and gives the getIt instance
CoreInjector.initialize();
//register mockUserService in place of actual user service in the CoreInjector.getIt
mockUserService = registerAndGetMock<UserService>(MockUserService());
// CoreInjector gives TravellerProfileViewModel, injected with UserService
travellerProfileViewModel =
CoreInjector.getIt.get<TravellerProfileViewModel>();
});
}
T registerAndGetMock<T>(T mockAble) {
_removeRegistrationIfExists<T>();
CoreInjector.getIt.registerFactory<T>(() => mockAble);
return mockAble;
}
Run Code Online (Sandbox Code Playgroud)
核心注入器代码
class CoreInjector {
static GetIt _getIt;
static GetIt get getIt => _getIt;
static …
Run Code Online (Sandbox Code Playgroud) unit-testing dependency-injection injectable flutter flutter-test
假设您在Value对象和Services对象中划分系统(如"面向对象的软件增长,测试指导"中所述.Misko Hevery称这些为"newables"和"injectables".
当你的一个值对象突然需要访问服务来实现它的方法时会发生什么?
假设你有一个很好的简单Value对象.它是不可变的,包含一些信息,而且就是它.假设我们使用类似这样的东西:
CreditCard card = new CreditCard("4111-1111-1111-1111", "07/10");
if (card.isValid())
{
// do stuff
}
else
{
// don't do stuff
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好. isValid()
在卡号上实现校验位算法并返回true/false.
现在,假设我希望通过验证当前时间的到期日来增强系统.您如何在不破坏Value对象/服务对象paradim的情况下完成此操作?我希望这个课程能够继续进行单元测试.
CreditCard
现在有一个依赖项,但由于它的创建方式,它无法注入,因此依赖注入已经完成.CreditCard
类不应该呼唤单身(我的位置,为一个Singleton全球访问是不好的做法)CreditCardVerificationService.validateCard()
手段意味着必须重新访问所有现有代码.isValid()的实现正在泄漏.我知道有一些事情可以解决这个问题,但最干净的方法是什么?
编写代码时,我们应该能够识别两大对象:
http://www.loosecouplings.com/2011/01/how-to-write-testable-code-overview.html
http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/
可注入对象是在其构造函数中公开依赖项的对象(服务),这些依赖项通常使用IoC容器解析,这些对象只能在其构造函数中请求其他注入项
Newable是在其构造函数中也暴露依赖项的对象,但是newables只能请求其他可新建对象(实体,值对象),新对象的另一个特征是它们不应该持有对可注入对象的引用
但是在编写代码时,我们经常需要将一个服务(可注入)"注入"到一个实体(newable)中
我一直在想,在一个新的对象中暴露服务依赖可能更好地在方法级别进行,但这听起来有很多工作要做....只是考虑在每次调用方法时解析依赖关系...这有点像我们必须使用服务定位器反模式
我解决这个问题的方法是:
使用公开依赖项的方法创建一个接口(该方法中将使用该服务)
为接口创建一个扩展方法,并将其放在不同的命名空间中,也许放在另一个程序集中,然后将调用包装到原始方法,使用服务定位器解析依赖项
这样做,我们可以在新的和可注射的对象之间保持一致的分离,并且能够轻松地在我们的新手中使用服务
extension-methods dependency-injection service-locator injectable newable
我正试图在我的应用程序中实现一个auth guard.即; 只有经过身份验证的用户才能访问我的应用的某些路由 我跟着这里给出的啧啧.
一旦用户登录,我将我的AuthService中的布尔值更改为true以指示该用户已登录.这需要在应用程序的整个生命周期中保留.
下面给出了源代码:
AUTH-guard.service.ts
import { Injectable } from '@angular/core';
import {
CanActivate, Router,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from '@angular/router';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuardService implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url: string = state.url;
return this.checkLogin(url);
}
checkLogin(url: string): boolean {
console.log('Auth Guard Service: ' + this.authService.isLoggedIn);
if (this.authService.isLoggedIn) { return true; }
// Store the attempted URL for …
Run Code Online (Sandbox Code Playgroud) 我有类似的东西:
@injectable
class SettingsBloc {
final Event event;
SettingsBloc(@factoryParam this.event);
}
Run Code Online (Sandbox Code Playgroud)
当我从代码中调用它时,我传递工厂参数,例如:getIt<SettingsBloc>(param1: Event())
但是,当 SettingsBloc 是某些东西的依赖项时,调用是自动生成的,如下所示:get<SettingsBloc>()
生成的代码:
gh.factoryParam<SettingsBloc, Event, dynamic>(
(event, _) => SettingsBloc(event));
gh.factoryParam<HotelsBloc, Event, dynamic>(
(event, _) => HotelsBloc(
event,
get<SettingsBloc>(),
));
Run Code Online (Sandbox Code Playgroud)
因此,工厂参数未传递,并且所有内容都会在运行时崩溃。我怎样才能解决这个问题?
PS 长话短说:应该有一种方法来生成此代码:
gh.factoryParam<HotelsBloc, Event, dynamic>(
(event, _) => HotelsBloc(
event,
get<SettingsBloc>(param1: event),
));
Run Code Online (Sandbox Code Playgroud)
而不是这个:
gh.factoryParam<HotelsBloc, Event, dynamic>(
(event, _) => HotelsBloc(
event,
get<SettingsBloc>(),
));
Run Code Online (Sandbox Code Playgroud) 可以这样做吗?(因为我试过,但没有成功):
@Injectable()
class A {
constructor(private http: Http){ // <-- Injection in root class
}
foo(){
this.http.get()...
};
}
@Injectable()
class B extends A{
bar() {
this.foo();
}
}
Run Code Online (Sandbox Code Playgroud)
在我的图书馆中,我有一个带有以下代码的服务:
import { Inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DataInjectorModule } from '../../data-injector.module';
// @dynamic
@Injectable()
export class RemoteDataService<T> {
@Inject('env') private environment: any = {};
public type: new () => T;
constructor(
model: T,
) {
this.http = DataInjectorModule.InjectorInstance.get(HttpClient);
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
(现有原因data-injector.module
只是避免循环依赖):
import { NgModule, Injector } from '@angular/core';
// @dynamic
@NgModule({
declarations: [],
imports: [],
providers: [],
exports: [],
})
export class DataInjectorModule {
static InjectorInstance: Injector; …
Run Code Online (Sandbox Code Playgroud) injectable ×10
angular ×6
typescript ×3
flutter ×2
newable ×2
singleton ×2
angular10 ×1
angular6 ×1
dart ×1
flutter-test ×1
inject ×1
oop ×1
service ×1
spyon ×1
unit-testing ×1