简体   繁体   中英

ES6 circular dependency. Implementing dependency hub

I found a lot of articles about circular dependencies and that it indicates the design/architecture flaws in the project. In most of the cases it can be fixed easily by slightly refactoring your classes.

In this example I'm trying to create a hub for dependencies. This is a library of classes that can be imported by different projects. The goal is to have getters in the main class that will return an instance of the dependency. This instance has to be a singleton and it's stored in the main class' dependencies that next time if someone calls a getter - it will return the same instance of that class.

Here is how code looks like:

// deps

import { DepA } from './dep-a';
import { DepB } from './dep-b';

const depsKey = '__MY_DEPS__';

class Deps {
  dependencies = {};

  get depA() {
    return this.getDependency('depA', DepA);
  }  
  
  get depB() {
    return this.getDependency('depB', DepB);
  }  

  bind(key, value) {
    this.dependencies[key] = value;
  }

  getDependency(key, serviceClass) {
    let service = this.dependencies[key];

    if (!service && !!serviceClass) {
      // if instance is not created yet, we instantiate the class and put instance in the dependencies
      service = new serviceClass();
      this.bind(key, service);
    }

    return service;
  }
}

export const deps = (() => {
  window[depsKey] = window[depsKey] || new Deps();

  return window[depsKey];
})();

// dep-a

import { deps } from './deps';

export class DepA {
  methodA() {
    console.log(deps.depB);
  }
}

// dep-b

import { deps } from './deps';

export class DepB {
  methodB() {
    console.log(deps.depA);
  }
}

As you can see - this creates a circular dependency problem, since class Deps uses classes DepA and DepB in its getters to create an instance of those classes if it doesn't exist. And classes DepA and DepB use an instance of Deps to retrieve each other via its getters.

I hope this explanation is not very cumbersome.

Can anybody suggest the changes I need to make to get rid of the circular dependency here but to keep an idea of accessing singletons via Deps class (deps instance)?

My recommendation would be this:

a-singleton.js

import { DepA } from './dep-a'; 

let singleton;
export function getA() {
  if (!singleton) {
    singleton = new DepA();
  }
  return singleton;
}

b-singleton.js

import { DepB } from './dep-b'; 

let singleton;
export function getB() {
  if (!singleton) {
    singleton = new DepB();
  }
  return singleton;
}

then wherever you need these singletons, you can import the file and call the function to get the singleton.

Depending on what these classes do and how/when they reference eachother, you may also be able to directly do export default new DepA() , but depending on how they reference eachother, and how much they need to do at instantiation time, the lazy approach I've shown here can be better or necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM