The Heart of the Publisher-Subscriber Design Paradigm

After reading various online articles on the Publisher-Subscriber pattern, I have found that many include unnecessary domain-specific components or unreliable information inconsistent with OOP standards.

I am seeking the most basic and abstract explanation of this pattern, without industry examples or real-world analogies. What are the essential classes needed to implement the Publisher-Subscriber design pattern in OOP?

What are the minimum classes required and what should their interfaces consist of, to represent the Publisher-Subscriber design pattern in OOP?

I would prefer clear and minimal code demonstrations, preferably in TypeScript or strictly-annotated Python.

Based on my research, it seems that the primary classes involved are:

class Publisher {}
class Subscriber {}
class Broker {}

Additional OOP constructs like Topic or Event may also be necessary, but I am unsure about the methods and attributes each class should contain.

Answer №1

In software architecture, the Publisher-subscriber pattern is centered around networks, while the Observer pattern focuses on individual objects and events. These patterns are utilized at various levels within software systems.

Essentially, the Observer pattern operates within the confines of an application or single process, whereas Publish-Subscribe facilitates communication across applications by exchanging messages between different processes.

When discussing the Observer pattern, only two classes are typically required:

  • Publisher or Subject: The source of events that listeners want to hear from.
  • Subscriber or Observer: Those who wish to receive events generated by the Publisher or Subject.

Here's an example showcasing abstractions for the Observer and Publisher (Subject):

interface IMyObserver
{
    update: (myMessage: string) => void;
}

interface IMySubject
{
    registerObserver: (o: IMyObserver) => void;

    removeObserver: (o: IMyObserver) => void;

    notifyObservers: () => void;
}

Below is a concrete implementation of the IMyObserver:

class MyObserver implements IMyObserver
{
    _mySubject: MySubject
    _myMessage: string | undefined

    constructor(mySubject: MySubject)
    {
        this._mySubject = mySubject;
        this._mySubject.registerObserver(this);
    }

    update(myMessage: string) : void {
        this._myMessage = myMessage;
        console.log(`The Observer has received this message: ${this._myMessage}`);
    }
}

This is a specific implementation of IMySubject:

class MySubject implements IMySubject
{
    _observers: IMyObserver[] = []
    _myMessage?: string 
    _messageFromObserver?: string

    notifyObservers()
    {
        this._observers.forEach(obs => obs.update(this._myMessage ?? ''))
    }

    
    registerObserver(o: IMyObserver):void { 
      this._observers.push(o) 
    }

    removeObserver(o: IMyObserver) {
      const index = this._observers.indexOf(o);
      if(index !== -1) {
        this._observers.splice(index, 1);
      }
    }

    myMessageChanged() { 
      this.notifyObservers()
    };

    setMessage(message: string)
    {
        this._myMessage = message;
        this.myMessageChanged();
    }
}

To execute the above code, follow these steps:

const mySubject = new MySubject();
const myObserver = new MyObserver(mySubject);

// Sending a message from the subject
mySubject.setMessage("Hello World!");

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why is the 'as' keyword important in TypeScript?

class Superhero { name: string = '' } const superheroesList: Superhero[] = []; const superheroesList2 = [] as Superhero[]; As I was exploring TypeScript, I stumbled upon these two distinct methods of declaring an array. This got me thinking w ...

Deciphering the .vimrc setup for tooltips and symbols in TypeScript

Currently, I have integrated the Tsuquyomi plugin for my typescript development in Vim. The documentation mentions tooltips for symbols under the cursor, which are working fine. The issue arises as I am using terminal-based Vim, and even if I were using a ...

React - Component not updating after Axios call in separate file

Recently I decided to delve into React while working on some R&D projects. One of my goals was to build an application from scratch as a way to learn and practice with the framework. As I started working on my project, I encountered a rather perplexin ...

When trying to click the button in Navbar.jsx, I encounter an error when attempting to invoke the setShowCart(true) function

I've encountered an issue while trying to call the setShowCart(true) function in Navbar.jsx. I'm unsure of how to fix this. import React from 'react' import Link from 'next/link'; import {AiOutlineShopping} from 'react-ic ...

Can you please provide information on the specific type of decorator used in Vuex, known as the 'vuex-class' decorator

My TypeScript project has the 'no-implicit-any' rule enabled, but I'm facing challenges when it comes to defining types for all of the 'vuex-class' decorators. For instance, when importing the namespaced action @(namespace('f ...

The validation for the email field in Bootstrap, specifically in Angular 5, is not functioning properly for the "Email is Required

As a newcomer to Angular, I am seeking assistance with validation in my Angular 5 application. Specifically, I need to validate user emails and only allow navigation to a new component when a valid email is entered upon clicking a button. While pattern va ...

Creating web components with lit-element, leveraging rollup, postcss, and the tailwind framework for packaging

I have been attempting to package a functional web component that was developed using the lit-element/lit-html with the tailwind framework utilizing the postcss plugin from the rollup packager. Upon conducting a rollup, I discovered the compiled js and ht ...

Testing the Express API with MongoDB on a local machine is successful but encounters a timeout issue on CircleCI

I am facing an issue with testing a RESTful API (built with Express in TypeScript) using Jest. The test passes successfully on my local Windows machine but times out on CircleCI. .circleci/config.ylm version: 2.1 jobs: build: docker: - image: ...

Tips for troubleshooting TypeScript files in Angular 2

It appears that the latest angular2 npm package does not provide a way to debug TypeScript sources. Previous solutions on Stack Overflow and Medium are outdated. I have raised an issue on GitHub, please show your support. There are two main problems: 1) ...

Rows in angular ag grid are vanishing when data is filtered

My ag grid includes custom components for each column, but I'm facing an issue where the components disappear when filtering the data. For example: the component inside the row To apply filtering, I use an input with a filtering function: <data-gr ...

How come the path alias I defined is not being recognized?

Summary: I am encountering error TS2307 while trying to import a file using an alias path configured in tsconfig.json, despite believing the path is correct. The structure of directories in my Angular/nx/TypeScript project appears as follows: project |- ...

What is the most efficient method for incorporating React into Wordpress while using Typescript?

Is it possible for me to utilize the React / React-Dom scripts that Wordpress has enqueued in my bundled javascript, while still being able to use the -dev installed React for development purposes? The javascript files are designed for a WordPress plugin ...

Utilize the power of relative import by including the complete filename

When working on my TypeScript project, I have noticed that to import ./foo/index.ts, there are four different ways to do it: import Foo from './foo' // ❌ import Foo from './foo/index' // ❌ import Foo from './foo/i ...

The promise briefly returns a placeholder object before resolving with the actual response

Currently, I am working on a simple check to determine whether myAnswer contains an answer. The checking functionality is operating smoothly; however, the issue arises in the final function that aims to return the string obtained from myAnswer. Instead of ...

The inability to destructure the 'store' property from the 'useReduxContext(...)' because of its null value

I am currently using NextJs 13 along with redux toolkit. Whenever I run the npm run build command, I encounter this error: "Cannot destructure property 'store' of 'useReduxContext(...)' as it is null." I suspect that the issue lies wi ...

Find the identifier that does not currently exist in the collection of objects

There is a situation where I have an array and an object that consists of arrays of ids, which are essentially permission objects. My goal now is to extract the ids that do not exist in the given object. Can someone assist me with devising the necessary l ...

User's information will only be updated once the page is refreshed

I am encountering an issue with displaying two ul elements based on user login status. When I log in, the first ul is shown immediately, but the second ul is only displayed after a page refresh. Initially, the value in "accountService.currentUser" is null ...

Having trouble with React npm start: 'No chokidar version found' error occurring

After cloning my React-Typescript app on Github Pages and attempting to make some changes, I encountered an issue. Despite running npm install to install all dependencies, when I tried to run npm start, I received the following error message: https://i.st ...

Strategies for iterating over an array in React with TypeScript

I'm currently working on looping through an array to display its values. Here's the code I have: ineligiblePointsTableRows() { return this.state[PointsTableType.INELIGIBLE].contracts.map(contract => { return { applied: (&l ...

Angular 2 - The creation of cyclic dependencies is not allowed

Utilizing a custom XHRBackend class to globally capture 401 errors, I have encountered a dependency chain issue in my code. The hierarchy is as follows: Http -> customXHRBackend -> AuthService -> Http. How can this problem be resolved? export cla ...