I'm currently using an globals object to store variables used by other objects.
globals.js
export default {
colors: {
bg: 0x000000,
front: 0xffffff
},
scene: new THREE.scene();
};
which allow me to do this in a given class:
Foo.js
import globals from './globals.js';
class Foo {
constructor() {
this.color = globals.colors.front;
// ...
globals.scene.add(this.mesh);
}
}
I'm wondering if this is a good way to work. Should I create a separate module for each object (say a colors.js file and a Scene.js) and import them wherever needed? Or is a globals object fine? I can't think of any drawbacks but it doesn't seem clean to me.
I'm learning patterns myself. This stuff does depend somewhat on your app and your particular needs.
Singleton's are often seen as an anti-pattern, but don't always have to be.
import globals from './globals.js';
class Foo {
constructor() {
this.color = globals.colors.front;
// ...
globals.scene.add(this.mesh);
}
}
const myFoo = new Foo()
globals.colors.front.set('red')
myFoo.color.set('blue') //its the same global color
How about this?
import globals from './globals.js';
class Foo {
constructor(color) {
this._color = color;
// ...
globals.scene.add(this.mesh);
}
}
const myFoo = new Foo(globals.colors.front)
globals.colors.front.set('red')
//myFoo._color.set('blue') //_ in name hints it's private and should not be used
This way your FOO only knows about a color that is passed. If it needs to manage and hold onto it's own color you would create an instance of THREE.Color on it, in the constructor. If it just needs to reference some color, than it could be hidden from the outside world, only caring about the reference passed to it (not caring what's in it).
Regarding the scene, you could create a manager of some kind and then whenever you ask for a new instance of Foo the manager would add it to the scene.
Related
I'm a bit new to React and I'm currently developing a Proyect which has a service layer. To do so, I created a function component which would have the methods as variables:
const CustomComponent = () => {
method1 = () => {...},
method2 = () => {...},
method3 = () => {...}
}
export default CustomComponent;
This component would then be imported to the component that will use it.
To make my architecture as clean as possible, I wanted to make some of the methods private. However, as you may already know, that is not possible to do in the solution I proposed. Do hoy have an idea on how to achieve this, or maybe there is a convention to make a service layer I'm not aware of?
Thank you so much in advance!
The architecture which I find particularly clean and maintainable is one where you split off logic from presentation into two files like this:
Service layer (ts):
export class Service implements ServiceInterface {
constructor(private instanceVariable: string = "foo") { }
private methodOne(): string {
return this.instanceVariable
}
public methodTwo(argumentVariable: string): string {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
interface ServiceInterface {
methodTwo(argumentVariable: string): string;
}
export default new Service();
Service layer (js):
export class Service {
instanceVariable;
constructor(contructorArgument) {
this.instanceVariable = contructorArgument;
}
methodOne() {
return this.instanceVariable
}
methodTwo(argumentVariable) {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
export default new Service();
Presentation layer:
import Service from "./service.ts";
const FunctionalComponent = () => {
const [localState, setLocalState] = useState(localStateInit);
return (
<>
<div>{Service.methodTwo("bar")}</div>
</>
)
}
Few things happen here (mostly regarding ts implementation).
Keep component's service and presentation layers in separate files.
Use an interface to describe the service class and its methods. This will help to work with your service layer in your component as you'll get Typescript's IntelliSense.
For this example I'm exporting an instance of the service as default export from its file. This gives you a cleaner API in your component's file, where you can call methods without having to "pollute" component file with instance creation. This has at least the following two drawbacks:
you mostly lose ability to work nicely with static class members
preconfigured instance variable (initiated as a private member in constructor) means its value cannot be replaced in testing.
If any of above are a no go, then clean up the constructor, export just the class itself and instantiate it as required in component file.
I'm also exporting the class itself. This is for testing purposes. In testing you want to be able to swap out arguments passed into class' constructor and you need to have class definition to do that.
You'll notice the shorthand notation for declaring and instantiating a private class variable in the constructor: private instanceVariable: string = "foo". This is equivalent to something like this:
class Service {
private instanceVariable: string;
constructor(constructorArgument: string) {
this.instanceVariable = constructorArgument;
}
Such notation is particularly nice when used with dependency injection.
Overall, this setup will help you with unit testing logic in your service layer, as you can test it like any other class. This comes particularly handy when there's a lot of conditional rendering logic.
Let me know if this is what you've been looking for. Maybe we could tailor it better for your use case.
I would like to have a class with some constants, so I can make calls such as:
const MyClass = require('./myclass.js');
console.log(MyClass.CONST1);
console.log(MyClass.CONST2);
let a = new MyClass();
...
My problem: I have to define a large amount of constants, so I would like to have a distinct block of code where the constants are defined, apart from my class definition:
a stand-alone object which defines the constants
the class definition
... And afterwards, merge them together into a single class definition so the caller use the constants as if they were part of the class definition.
Here is the way I found to do so, but I don't know if this is correct or if it could lead to some problems:
myclass.js
const MYCONSTANTS = {
CONST1: 1,
CONST2: 2
};
class MyClass {
constructor() {
}
}
// "merge" constants into MyClass
let exportedClass = Object.assign(MyClass, MYCONSTANTS);
// freeze exportedClass in order to forbid any change in constants values
Object.freeze(exportedClass);
// export
module.exports = exportedClass;
It seems to work, but I am not sure the way I "extend" the class is correct: I manipulate MyClass as if it was a variable (with Object.assign). Maybe there is a better/safer way to achieve this ?
class Line extends Shape {
static howToDrag = { point: 0, update: 'xy' }
static config = { color: 'white' }
render() {
console.log('render based on this.config', this.config)
}
}
class Shape {
constructor({ config }) {
this.constructor.howToDrag = expandProperty1(this.constructor.howToDrag)
this.config = config || this.constructor.config
}
drag() {
console.log('drag based on this.constructor.howToDrag ', this.constructor.howToDrag)
}
}
function expandProperty1({ point, update }) {
if (typeof update === 'string') {
return {
point,
update: {
[point]: update
}
}
}
}
Here is the code, If you can understand what I am doing, skip the following explanation and provided some suggestions on what is the better way to make use of OOP because the current implementation is pretty wired from my perspective.
Check out http://canvas-chart.herokuapp.com/ to see what I am doing and I will explain the code above.
Let us talk about the static property config first. config should belong to each instance, i.e. each instance should have its own config, why I put it as static? The reason is that there is some common logic related to config, i.e. it should be the value passed from the constructor, otherwise, it has the default value. By setting the config as static, I am able to implement such common logic in 'Base' class, rather than write it over and over again in each Derived class
The other concern is howToDrag, it is a real static.However the static is used by base class but defined in the derived class, is it a normal thing? What is more, the static property in the derived class is mutated in the base class.
The current make logical sense but I always wonder if it is the way to do OOP because it relies on the fact this.constructor is base class point to the derived class.
While I'm not huge into forcing OOP into a functional language, I'm struggling to understand what a peer of mine did to export modules from a Class. All I'm looking for is what to call this so I can continue to do research. From what I understand they were including some external SDK to be passed into an internal class which would inherit everything into the LibIncludes. This is suppose to allow all of the classes to inherit into the LibIncludes and LibIncludes inherits from Object. What I'm running into now is that anytime I try to call LibIncludes.Handlers; and execute a function included in Handlers I'm getting undefined. I can't figure out what pattern he applied to make this work and everything in ES6 shows an entirely different approach to exporting and importing between classes for inheritance. Any help would be greatly appreciated.
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
class LibIncludes {
static compose() {
const Handler = new HandlerSvc(ExternalSdk);
return {
Handler
};
}
}
module.exports = LibIncludes;
let function = LibIncludes.sdkFunciton;
// function should be invoked and return some object
Here's the solution I came up with for refactoring. It seems cleaner and without the static members:
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
module.exports = class LibIncludes {
constructor(handler) {
this.handler = new HandlerSvc(ExternalSdk);
}
}
// app.js
const lib = require('./index');
var getSomething = new lib();
console.log(getSomething.handler);
// function should be invoked and return some object
This is weird. What am I doing wrong?
class Store extends Riot.Observable {
trigger():void {
// shouldn't this be completely overwriting the trigger method on riot.observable?
console.log("my trigger....");
}
}
let store = new Store();
store.trigger();
Expected behaviour: "my trigger...." in the console. What I get is the original implementation of trigger on the Riot.Observable, which errors because of no parameters being passed.
If I poke the store object I can see on store.__proto__ does have trigger on there, with my implementation. But store iself has its own (original) copy of trigger()
Please see https://jsfiddle.net/sidouglas/5spbvpnn/
I referenced this with a very basic example, and I don't know what's going on.
Based on the source, riot observables do not take advantage of prototypical inheritance. They work as mixins instead. The typescript wrapper class just calls the original riot mixin. To overwrite a function, you have to assign it to the instance:
class Store extends Riot.Observable {
constructor() {
this.trigger = function() {
console.log("My trigger");
};
}
}
let store = new Store();
store.trigger();