Инкапсуляция состояния / возможность подписаться на текущее состояние

Один из компонентов моего приложения должен подписаться на статьи, отмеченные (помеченные закладками):

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()
)
Другие вопросы по тегам