Инкапсуляция состояния / возможность подписаться на текущее состояние
Один из компонентов моего приложения должен подписаться на статьи, отмеченные (помеченные закладками):
getStarredArticles(): Observable<Article[]> {
return this.getArticles().pipe(
map((articles: Article[]) =>
articles.filter((article: Article) =>
article.state instanceof StarredArticleState
)
)
);
}
Article
переходы между состояниями управляются с помощью шаблона состояний:
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(); }
}
я хочу сделать Article
государственная собственность частная. Но тогда мне нужно подписаться на отмеченные статьи. Я подумал о добавлении строкового тега только для чтения вArticleState
интерфейс + добавить геттер в Article
:
class StarredArticleState implements ArticleState {
readonly tag: string = "starred"
...
articles.filter((article: Article) =>
article.stateTag === "starred"
)
Но это тоже не кажется хорошим решением.
Как я могу это решить?
1 ответ
Простое решение - добавить boolean
поле isStarred
чтобы обозначить, если Article
помечен.
Используя этот подход, вы можете удалить подход реализации интерфейса и сделать статью констатирующей класс (поскольку абстракция InitialArticleState
а также StarredArticleStatus
больше не требуется (разница между исходной статьей и статьей, отмеченной звездочкой, выражается в значении boolean
поле, а не тип реализации класса):
class ArticleState {
private isStarred: boolean = false;
public star(): ArticleState {
this.isStarred = true;
return this;
}
public unstar(): ArticleState {
this.isStarred = false;
return this;
}
public isStarred(): boolean {
return this.isStarred;
}
}
В Article
затем можно обновить класс:
export class Article {
// ...keep existing implementation...
public isStarred(): boolean {
return this.state.isStarred();
}
}
Затем вы можете просто отфильтровать по isStarred()
метод:
articles.filter((article: Article) =>
article.isStarred()
)