常用设计模式和方法
- 依赖注入(Dependency Injection):通过将服务注入到指令中,使指令依赖于抽象的服务接口而非具体实现,降低指令与服务的耦合度。例如在Angular中,使用
@Injectable()
装饰器标记服务,在指令构造函数中声明依赖,Angular的注入器会自动提供实例。
- 观察者模式(Observer Pattern):允许指令和服务之间建立一种发布 - 订阅关系,当服务中的数据发生变化时,相关指令能够收到通知并作出相应反应,实现了数据的单向流动,减少直接依赖。
- 单例模式(Singleton Pattern):确保整个应用中某个服务只有一个实例,指令通过依赖注入获取这个单例实例进行交互,避免了多个实例带来的不一致性和高耦合。
观察者模式在指令与服务交互场景下的应用及优势
- 应用:
- 服务端:服务维护一个观察者列表,当服务中的数据发生变化时,遍历这个列表并通知所有观察者。例如,有一个
UserService
,它管理用户的登录状态。在UserService
中定义一个BehaviorSubject
来表示用户登录状态:
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserService {
private _isLoggedIn = new BehaviorSubject<boolean>(false);
public isLoggedIn$ = this._isLoggedIn.asObservable();
login() {
// 模拟登录逻辑
this._isLoggedIn.next(true);
}
logout() {
// 模拟登出逻辑
this._isLoggedIn.next(false);
}
}
- 指令端:指令订阅服务中的可观察对象。例如,有一个
ShowLoginButtonDirective
指令,根据用户登录状态决定是否显示登录按钮:
import { Directive, ElementRef, HostBinding, OnInit } from '@angular/core';
import { UserService } from './user.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Directive({
selector: '[appShowLoginButton]'
})
export class ShowLoginButtonDirective implements OnInit {
@HostBinding('style.display') display = 'none';
private destroy$ = new Subject<void>();
constructor(private userService: UserService, private el: ElementRef) {}
ngOnInit() {
this.userService.isLoggedIn$.pipe(
takeUntil(this.destroy$)
).subscribe((isLoggedIn) => {
if (isLoggedIn) {
this.display = 'block';
} else {
this.display = 'none';
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
- 优势:
- 解耦:指令和服务之间没有直接的强依赖关系,服务只负责发布数据变化,指令只负责订阅感兴趣的数据变化,两者的耦合度大大降低。例如,如果服务的实现方式改变,只要其发布的数据结构不变,指令不需要进行大的改动。
- 可维护性:当需要增加新的指令来响应服务数据变化时,只需要在新指令中订阅服务的可观察对象,而不需要修改服务和其他指令的代码,提高了代码的可维护性。
- 灵活性:可以有多个指令同时订阅服务的同一个数据变化,实现了一对多的关系,增加了应用的灵活性。