The Article model supports a bunch of transitions. Only two are shown below: star()/unstar().
interface ArticleState {
star(): ArticleState;
unstar(): ArticleState;
// other transitions ...
}
export class InitialArticleState implements ArticleState {
star = () => new StarredArticleState();
unstar = () => this;
// other transitions ...
}
export class StarredArticleState implements ArticleState {
star = () => this;
unstar = () => new InitialArticleState();
// other transitions ...
}
export class Article {
state: ArticleState = new InitialArticleState();
star() { this.state = this.state.star(); }
unstar() { this.state = this.state.unstar(); }
}
The Article state operations are wrapped by the service which updates the feed:
@Injectable()
export class ArticlesFeedService {
private feed$: Subject<Article[]> = new BehaviorSubject<Article[]>([]);
private store: Article[] = [];
private publishChanges() {
this.feed$.next(this.store);
}
starArticle(article: Article): void {
article.star();
// update the store then publish changes...
}
}
There's a component subscribed to get starred articles:
getStarredArticles(): Observable<Article[]> {
return this.getArticles().pipe(
map((articles: Article[]) =>
articles.filter((article: Article) =>
article.state instanceof StarredArticleState
)
)
);
}
My motivation behind using the state pattern is that it helps reduce branching (decision making) in the feed service methods (e.g. starred article can't be blacklisted, only unstarred / initial).
- Is it okay to use state as public property of the
Article? - How can I improve the design?
- Are there any TypeScript features that could be used instead?
Aucun commentaire:
Enregistrer un commentaire