/* * Copyright [2019] [Doric.Pub] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ export type Observer = (v: T) => void export type Updater = (v: T) => T export interface IObservable { addObserver(observer: Observer): void removeObserver(observer: Observer): void update(updater: Updater): void } export class Observable implements IObservable{ private provider: IProvider private clz: { new(...args: any[]): M } private observers: Set> = new Set constructor(provider: IProvider, clz: { new(...args: any[]): M }) { this.provider = provider this.clz = clz } addObserver(observer: Observer): void { this.observers.add(observer) } removeObserver(observer: Observer): void { this.observers.delete(observer) } update(updater: Updater): void { const oldV = this.provider.acquire(this.clz) const newV = updater(oldV) if (newV !== undefined) { this.provider.provide(newV) } for (let observer of this.observers) { observer(newV) } } } export interface IProvider { provide(obj: Object): void acquire(clz: { new(...args: any[]): T }): T | undefined remove(clz: { new(...args: any[]): T }): void clear(): void observe(clz: { new(...args: any[]): T }): Observable } export class Provider implements IProvider { private provision: Map = new Map private observableMap: Map> = new Map provide(obj: Object) { this.provision.set(obj.constructor, obj) } acquire(clz: { new(...args: any[]): T }): T | undefined { const ret = this.provision.get(clz) return ret as T | undefined } remove(clz: new (...args: any[]) => T): void { this.provision.delete(clz) } clear(): void { this.provision.clear() } observe(clz: new (...args: any[]) => T): Observable { let observable = this.observableMap.get(clz) if (observable === undefined) { observable = new Observable(this, clz) this.observableMap.set(clz, observable) } return observable } }