[英]Angular Local and Session reusable methods Design pattern
我將數據存儲在瀏覽器的本地和 Session 存儲中。 實施本地和 Session 存儲服務的良好設計實踐是什么? 我有一個用於處理 json 的通用服務。
@Injectable()
export class StorageService {
private storage: any;
constructor() {
this.storage = sessionStorage;
}
public retrieve(key: string): any {
const item = this.storage.getItem(key);
if (item && item !== 'undefined') {
return JSON.parse(this.storage.getItem(key));
}
return;
}
public store(key: string, value: any) {
this.storage.setItem(key, JSON.stringify(value));
}
public remove(key: string) {
this.storage.removeItem(key);
}
}
如您所見,目前它與 Session 一起使用。 我還需要處理本地。
public removeLocal() { .. }
public removeSession() { .. }
private remove(key: string, storage: Storage) {
storage.removeItem(key);
}
這是可以使用策略模式的地方:
策略模式是一種行為軟件設計模式,可以在運行時選擇算法。 代碼不是直接實現單個算法,而是接收運行時指令,以確定要使用一系列算法中的哪一個。
讓我舉個例子。
我們需要有一些共同的行為,這些行為將在所有策略中共享。 在我們的例子中,它將是 session 或本地存儲的 CRUD 方法:
export interface Storage {
retrieve(key: string): string | null ;
store(key: string, value: string): void;
remove(key: string): void;
}
以及它的具體實現。 這些是可交換的策略:
export class LocalStorage implements Storage {
retrieve(key: string): string | null {
return localStorage.getItem(key)
}
store(key: string, value: string): void {
localStorage.setItem(key, value);
}
remove(key: string): void {
localStorage.removeItem(key);
}
}
export class SessionStorage implements Storage {
retrieve(key: string): string | null {
return sessionStorage.getItem(key)
}
store(key: string, value: string): void {
sessionStorage.setItem(key, value);
}
remove(key: string): void {
sessionStorage.removeItem(key);
}
}
這是一個 class 將執行策略:
export class StorageService {
public storage: Storage;
constructor(storage: Storage) {
this.storage = storage;
}
retrieve(key: string): string | null {
return this.storage.retrieve(key)
}
store(key: string, value: string): void {
this.storage.store(key, value);
}
remove(key: string): void {
this.storage.remove(key);
}
}
然后我們可以這樣稱呼我們的策略:
const storage = new StorageService(new LocalStorage())
storage.store('some key', 'some value')
這種設計符合開閉原則。 因此,如果您需要添加其他存儲,則:
StorageService
class並且符合開閉原則。
感謝Wiktor Zychla的評論:
客戶端仍然必須直接決定將哪個存儲傳遞給存儲服務。 每次客戶端需要存儲服務時,都需要通過一個具體的實現:new StorageService(new LocalStorage())。 向前邁出的一步是將 new LocalStorage() 隱藏在工廠 new LocalStorageFactory().Create() 后面,以便固定 API 調用,但可以在某處重新配置工廠,例如取決於配置。
是的,這是真的。 所以我們需要一個可以存儲所有策略的地方。 我們應該能夠從這家商店獲得必要的策略。 所以這是一個可以使用簡單工廠的地方。 簡單工廠不是工廠方法模式,也不是抽象工廠。
export class StorageFactory {
#storagesByKey : Record<string, Storage> = {
'local': new LocalStorage(),
'session': new SessionStorage(),
}
getInstanceByKey(key: string) {
return this.#storagesByKey[key];
}
}
然后您可以更輕松地獲得所需存儲的實例:
const storageFactory = new StorageFactory();
const storage = new StorageService(storageFactory.getInstanceByKey('local'))
storage.store('some key', 'some value')
我不會為此使用服務。 它可以是適合各種用途的簡單 class。
class MyStorage {
constructor(
private storage: Storage,
private readonly prefix = '',
) {}
private createKey(key: string): string {
return this.prefix ? `${this.prefix}-${key}` : key;
}
public retrieve<T = any>(key: string): T {
const item = this.storage.getItem(this.createKey(key));
try {
if (item && item !== 'undefined') {
return JSON.parse(item);
}
} catch { }
return;
}
public store<T = any>(key: string, value: T): void {
this.storage.setItem(this.createKey(key), JSON.stringify(value));
}
public remove(key: string): void {
this.storage.removeItem(this.createKey(key));
}
}
這款的主要賣點是:
prefix
- 稍后,當您在不同的地方多次使用它時,前綴將確保您沒有名稱沖突。export const userSettingsSotrage = new MyStorage(localStorage, '[USER]');
userSettingsSotrage.retrieve<User>('user'); // Just a shorthand for "as User"
userSettingsSotrage.store<User>('user', userOrUndefined); // Error
userSettingsSotrage.store<User>('user', user); // OK
如果你想要更多的類型安全,你可以給整個MyStorage
generics 來定義存在的鍵及其類型。 您甚至可以通過將值解析為您想要的特定 class 的方式來執行此操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.