4
\$\begingroup\$

I have some validation classes. To keep things smooth, I create a single class that has those validation classes inside of it. That class will be a singleton, and gets injected into my other classes.

The validation classes have a method that needs to be executed by the depending object. So lets make this clear:


The Matrix class

Gets a validate class injected

and calls validate.validateMatrix().


That method, validateMatrix(), is actually in another class, that validate imports and creates a reference to. The validateMatrix class, for example, looks like this:

export class validateMatrix {
    validateMatrix(props){
       ...
    }
}

The validateclass has a generator for those classes that it needs, and all the validation classes have a method with the exact same name as the class name. That way, I can request the class name and call out to the validate method. That class looks like this:

import {validateString} from './validate/validateString';
import {validateSlider} from './validate/validateSlider';
import {validateCheckbox} from './validate/validateCheckbox';
import {validateRadio} from './validate/validateRadio';
import {validateDatetime} from './validate/validateDatetime';
import {validateMatrix} from './validate/validateMatrix';

export class validate {

    // this is just the library containing all the validators, for easy import.

    constructor(){
        this.classGenerator(
            validateString,
            validateSlider,
            validateCheckbox,
            validateRadio,
            validateMatrix,
            validateDatetime
        );
    }

    classGenerator(...classes){
        // pass in a class with the same method name as class name
        // and that function will be referred from here
        // e.g. this.validateMatrix()

        classes.forEach( (theClass) => {
            let classObj = new theClass();
            this[classObj.constructor.name] = classObj[classObj.constructor.name];
        });
    }
}

Usage:

validate() {
    this.validator.validateMatrix(this.question.properties)
        .then(this.branching.branch());
}

Is this a good way to create a factory method to generate those methods, and keep them hidden in other classes?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Your solution works, and is perfectly functional, but it's bad practice.

What you're describing is the service locator anti-pattern, it means that instead of passing what you need to a function, you pass a magic box that holds what you need and many other things, and it's the responsibility of your consuming class to know this magic box (called a service locator), and be tightly coupled with it, to get the object it really needs. It's a redundant layer of abstraction that only makes things harder instead of easier.

Do you have a Matrix class? Pass it a MatrixValidator with a .validate() method. Have a Checkbox class? Pass it a CheckboxValidator with a .validate() method.

This way, your actual classes don't need to know anything about their validators, they only see an object with a .validate() method, and the .validate() method gets implemented differently for each validator. That's called polymorphism, and it's a powerful tool in your OO arsenal.

Additionally, dynamically adding methods to constructors (a.k.a. classes) is frowned upon, because it makes it hard to read. With the polymorphism method, all of your methods are known at write time, and nothing is added in runtime, which is good for both readability and performance.

Now, you might ask, "who will determine which Validator instance to inject to each of my classes", that would be "the entity that creates your instances", normally, that would be a factory of some sort, otherwise, look up Dependency Injection for a good pattern to follow.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.