javascript good way to create or design Singleton class - javascript

I think in javascript it could create Singleton class like below
test.js
class Container {
constructor() {
this.map = new Map;
}
set(key, value) {
this.map.set(key, value);
}
get(key) {
return this.map.get(key);
}
}
module.exports.Container = new Container();
so that
I could use that other files like in index.js
import container from './test'
However the constructor of Container need some other parameters so that it could do better. And the Container also need to be Singleton class ,
because it is a common class . And i do not know how to create it?
constructor(servie) {
this.map = new Map;
this.servie = servie;
}
by the way the service variable is created when application starts

EDIT: I've realised my naming is slightly confusing, as I've used Container to represent the IoC container, and then realised you've used that name to represent your Singleton.
Providing you are able to instantiate your singleton at a central point of code (entry point file for example, while setting up server). You can achieve a Singleton in a number of ways. For example:
let instance = null;
class Singleton {
constructor(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
}
module.exports = (...args) => {
return instance || (instance = new Singleton(...args));
}
You could do this any multitude of ways e.g. with static functions instead of the anonymous function. However, with all of these I think it becomes slightly confused as to whether you're init'ing the instance or just trying to retrieve it.
IoC container patterns (often used in C# projects) are a little cleaner in my opinion. Where you might have a single container class that keeps track of your singletons and provides separate access and initiation functions.
class Container {
constructor() {
this.instances = {};
}
add(name, instance) {
this.instances[name] = instance; // depends if you want overwrite or not
}
get(name) {
if (!this.instances[name]) {
throw new Error('some appropriate error messaging for your app');
}
return this.instances[name];
}
remove(name) {
delete this.instances[name];
}
}
module.exports = new Container(); // this has to be a no-param constructor
Then in your app init code, you initialise the singletons and register them with your container:
const Container = require('<path_to_Container>');
const Singleton = require('<path_to_Singleton>');
...
Container.add('mySingleton', new Singleton(arg1, arg2));
and access it at any time with:
Container.get('mySingleton');
Couple notes:
You could use Singleton.name instead of a string name ('mySingleton' in the example)
This is just a personal preference. But I like it because it feels more declarative, you register (add) an instance to the container at app start-up and don't blur the lines between initialisation and usage. And it means that if you add more of these singletons going forward, you have a single pattern for it already in place.

Related

Creating a frozen object for modules outside

class Model {
this.prop1 = "someKey",
this.prop2 = "someKey1",
anyMethod(valueForProp1, valueForProp2) {
this.prop1 = valueForProp1;
this.prop2 = valueForProp2;
}
}
exports.createModel = () => new Model();
The logic I am trying to create with the above code is as follows;
I do not want to give direct access to this class from any external module.In other words, new properties cannot be added to the objects of this class, and also the existing properties (like prop1, prop2) cannot be changed.The properties of objects of this class can only be changed by the methods(like anyMethod) in this module.
JS doesn't support private members/methods yet. So currently you are unable to force this kind of functionality.
The most agreed-upon convention (for JS) is to add a prefix of _ to any "private" members.
class Model {
this._prop1 = "someKey",
this._prop2 = "someKey1",
anyMethod(valueForProp1, valueForProp2) {
this._prop1 = valueForProp1;
this._prop2 = valueForProp2;
}
}
exports.createModel = () => new Model();
Outer solutions usually involve a 3rd party static type checker (like Typescript or flow) but this adds additional complexity to the code base that I don't know if you like or need.

How to specify return type of class constructor (e.g. using proxy)?

I'm pretty new to the Typescript world. Trying around with it a little more I stumbled across a problem when using a Proxy as a returned value from a class constructor.
Imagine the following code:
class Container {
constructor() {
return new Proxy(this, containerProxyHandler);
}
}
const container = new Container();
container.sessionStorage = () => {
return new SessionStorage('SESSION_ID');
};
container.session = factory(() => {
return new Session(container.sessionStorage);
});
container.random = protected(() => {
return Math.random();
});
The Container type is intended to be used as a dependency injection container. So assigning the properties inside the Container class is not possible due to the variable amount of services it will store.
When validated it complains about missing properties sessionStorage, session and random inside the Container type when assigning arrow functions to them.
Property 'sessionStorage' does not exist on type 'Container'
I could of course assign a type to the container variable myself via as or use a factory function, but find this approaches cumbersome for other people to use for example in case of library.
const container = new Container() as { [key: string]: any };
Is there an easier solution for this without the need of extra boilerplate code?
You can create an interface for it:
interface SomeType {
[name: string]: any;
}

Proper way to chain require

I am new to node and npm so thanks for bearing with me here.
I want to package/modularize a series of classes(in separate files) that inherit from a base class and all classes should be visible to the end user/programmer. In other words I want to preserve the previous requires so that I have a master object the end user can require to get everything. require('Event') also requires Item for the user/programmer.
"use strict";
const Item = require('./Item');
module.exports = class Event extends Item {
constructor() {
super();
this.TypeName = 'Event';
this.JSON = '{}';
}
static Bind(service, eventId) {
return new Event();
}
}
and
"use strict";
module.exports = class Item {
constructor() {
this.TypeName = 'Item';
this.JSON = '{}';
}
static Bind(service, itemId) {
return new Item();
}
}
Thanks for your help!
If you want to export multiple things from a a module, then you export a parent object and each of the things you want to export is a property on that object. This is not "chaining" as there really isn't such a thing for exporting multiple top level items from a module.
module.exports = {
Event, Item
};
class Item {
constructor() {
this.TypeName = 'Item';
this.JSON = '{}';
}
static Bind(service, itemId) {
return new Item();
}
}
class Event extends Item {
constructor() {
super();
this.TypeName = 'Event';
this.JSON = '{}';
}
static Bind(service, eventId) {
return new Event();
}
}
Then, someone using this module would do:
const m = require('myModule');
let item1 = new m.Item();
let event1 = new m.Event();
Or, you can assign them to top level variables within the module:
const {Item, Event} = require('myModule');
let item1 = new Item();
let event1 = new Event();
If you have multiple classes each in their own file and you want to be able to load them all with one require() statement, then you can create a master file that does a require() on each of the individual files and combines them into one exported object. Then, when you want to import all of them, you can just require in the master file.
node.js modules are designed such that you require() in everything you need in that module and you do that in each module that wants to use something. This enhances reusability or shareability of modules because each module independently imports the things it needs. You don't have all this global state that has to be imported somewhere before any of the other modules work. Instead, each module is self-describing. It also makes it much more obvious to people working on a module what it depends on because there's a require() statement for everything it depends upon. This may seem like a bit of extra typing for people coming from different environments where you might just import something once into a global namespace (and it is more typing), but there are very good reasons it is done this way and honestly, it doesn't take long to get used to it and then you can enjoy some of the benefits to doing it this way.

Node.js: exporting class/prototype vs. instance

As I do most of my programming in Java, I find it compelling to export a class in a Node.js module instead of an object instance, e.g.:
class Connection {
constructor(db) {
this.db = db;
}
connect(connectionString) {
this.db.connect(connectionString);
}
}
exports.Connection = Connection;
Since doing this would require instantiating the class multiple times across dependent modules, I still need to export an already existing instance for use in the rest of the production code. I do it in the same module:
exports.connection = new Connection(require("mongoose"));
This allows for some testability, as the real dependency can be swapped in a test:
const Connection = require("./connection").Connection;
describe("Connection", () => {
it("connects to a db", () => {
const connection = new Connection({connect: () => {}});
// ...
});
});
This approach works, but it has a strange feel to it as I'm mixing two patterns here: exporting a prototype (for unit tests) and an instance (for the production code). Is this acceptable? Should I continue with this or change to something different? If so, what is the preferred pattern?
You're right, it's a bad coding style, but actually you can write a function which, depending on the received parameter, returns either the single instance (for the whole application), or the class itself (for testing). Something like this:
class MyClass() {}
const instance = new MyClass();
function getInstanceOrClass(isTesting) {
if(isTesting) {
return MyClass;
} else {
return instance;
}
}
exports.getInstanceOrClass = getInstanceOrClass;
// in other files
const getInstanceOrClass = require('./yourFileName');
const classSingletonInstance = getInstanceOrClass();
// in test files
const getInstanceOrClass = require('./yourFileName');
const MyClass = getInstanceOrClass(true);

javascript - Check if parent methods are used inside child methods

I'm writing some JS that extends a parent class and I wanted to know if there's a way to tell if a child class is using a parent method without having called it yet. Ideally I'd like to run a check in the constructor of the parent to see if any of the child methods are using the parent's methods in the method definition.
I've done a bit of research and have come across things like Object.getOwnPropertyNames() but I'm not sure if I'm headed in the right direction.
For instance:
class Path {
constructor (name) {
// how can I check if addRelationship have been used? If possible.
this.relationships = {};
this.currentRelationship = '';
this.path = path;
}
addRelationship (relationship) {
// do something
this.currentRelationship = relationship.path;
return this;
}
makePath () {
let path = [this.path];
if(this.currentRelationship) {
path.push(this.currentRelationship)
}
return path.join("/");
}
}
class OnePath extends Path {
// ...
someMethodFromThatRelationship () { }
}
class TwoPath extends Path {
// ...
}
var onePath = new OnePath('one');
var twoPath = new TwoPath('two-path');
class SomeOtherPath extends Path {
one () {
return this.addRelationship(onePath);
}
two () {
return this.addRelationship(twoPath);
}
}
The idea of the above example is I could check if addRelationship is referenced in any methods and if so, register a this.relationships.one and this.relationships.two before one() and two() are actually called. I hope I'm making sense. I'd love to know if this is even possible.
Updated
The end result of the above code would be the ability to do the following:
let someOtherPath = new SomeOtherPath('some-other-path');
// now I can call
someOtherPath.relationships.one.someMethodFromThatRelationship();
// and can also call the save method from the extended class
someOtherPath.one().makePath();
// some-other-path/one
// I can also just call
someOtherPath.makePath();
// some-other-path
Is there a way to tell if a child class is using a parent method without having called it yet?
No. Figuring out what programs do without calling them is equivalent to the unsolvable halting problem.
I think what you are actually looking for is a more declarative approach for creating the relationship and its accompanying method in one go. Don't use too much magic (which a parent constructor inspecting its child class code would certainly be) but be explicit.
class Path {
constructor (path) {
this.relationships = {};
this.currentRelationship = '';
this.path = path;
}
addRelationship (name, relationship) {
this.relationships[name] = relationship;
this[name] = function() {
// do something
this.currentRelationship = name;
return this.relationships[name];
}
return this;
}
makePath () {
let path = this.path;
if (this.currentRelationship) {
path += "/" + this.relationships[this.currentRelationship].makePath();
}
return path;
}
}
class SomeOtherPath extends Path {
constructor(name) {
super(name);
this.addRelationship("one", new OnePath('one'));
this.addRelationship("two", new TwoPath('two-path'));
}
}
or even
class Path {
constructor (path, relationships = {}) {
this.relationships = relationships;
this.currentRelationship = '';
this.path = path;
for (let const r in relationships)
this.addRelationship(r, relationships[r]);
}
…
}
class SomeOtherPath extends Path {
constructor(name) {
super(name, {
one: new OnePath('one'),
two: new TwoPath('two-path')
});
}
}
Maybe you don't even need these child classes any more if they don't have other methods or are only instantiated once (as singletons).
Notice that the above approach will create new methods and new subpaths on every instantiation of the constructor, if you don't want that you can of course also put the declaration on the class statically. Just make addRelationShip a static method that initialises the default relationships objects and puts the methods on the class' .prototype. The variations of the pattern are endless.
You even might want to experiment with the proposed decorators feature for classes.

Categories

Resources