Quick Yet NOT dirty — lazy form of the Observer Pattern

Let’s cause some reactions and easily share state with just a few lines of code.

Disclaimer: This post won’t teach you the “observer pattern”.

In this quick post I’ll share a use case I had and how I resolved it without importing an external tool.

On one of my side projects, (emulated looper), the view layer (couple of buttons) must update the logic layer whenever a state changes.

The logic layer will react accordingly.

It’s a Typescript project, and I’m not using any framework, just the DOM and I.

In such case, I don’t see any point of using an external tool — (I like working with rxjs Subjects btw, awesome lib 😎 👏 ).

Here’s the code!

The observer pattern is a very common software design pattern. Its implementation is usually buried deep inside third-party libraries, so you have probably used it many times in the past, without even being aware of it..

The familiar implementation for making a reusable generic “subject” by a dedicated class.

I felt I don’t even need that, I only have 2 components on my project — so I just wrote the following 14 lines:

static viewInteractionSubject: ObserverType = {

observers: [],



on: (action: { name: string, fn: Function}) => {

LooperViewLayer.viewInteractionSubject.observers.push(action);

},



dispatch: <T>(name: string, arg?: T) => {

if (LooperViewLayer.viewInteractionSubject.observers.length === 0) return;

const exec = LooperViewLayer.viewInteractionSubject.observers

.find((event) => event.name === name);

exec.fn(arg);

}

};

I wouldn’t use that on a large project (e.g. at work), it’s not DRY for scaling up, there are some improvements I could do — e.g. adding unsubscribe function, using unique identifier like symbol instead of “name” string etc.. but it’s fine for that specific case.

And following is the way to use that from wherever entity that should respond to the view (hopefully there’s just one).

// Subscribe to view interactions

LooperViewLayer.viewInteractionSubject

.on({name: 'startRecording', fn: () => this.mediaRecorder && this.mediaRecorder.start()});



LooperViewLayer.viewInteractionSubject

.on({name: 'stopRecording', fn: () => this.mediaRecorder && this.mediaRecorder.stop()});

I want to thank Uri Shaked for thinking that this topic is worth mentioning and reviewing this post for me :)

That’s all,

Cheers, Liron.