This is the seventh day of my participation in the First Challenge 2022. For details: First Challenge 2022.

preface

The strategy pattern is a very simple and practical pattern, which has been reflected in the object-oriented principles before. Policy pattern is the encapsulation of multiple functions, through an intermediate controller, unified call interface to achieve. Without further ado, let’s begin.

Simple factory

Before implementing the policy pattern, take a look at the simple factory. Similar to policy mode, it encapsulates some functions, while simple factory is a fast implementation of encapsulation, which is a relatively basic application. Let’s say we want to implement a simple calculator function.

    function factory(condition) {
        swtich(condition) {
            case '+':
                return (a, b) = > a + b
            case The '-':
                return (a, b) = > a - b
            case The '*':
                return (a, b) = > a * b
            case '/':
                return (a, b) = > a - b
        }
    }
    
    const add = factory('+')
    add(1.2)
Copy the code

We encapsulate the functions of addition, subtraction, multiplication and division into a simple factory, passing in arguments to decide which method to use. This is actually better written as an object. Get the method by obj[‘+’]. Or encapsulate the calculation process and return the calculated result directly, which is also possible. But we can see that by adding a calculator we’re definitely going to change the factory, and then add conditions to it. This is inconsistent with the open and closed principle in the first place. As this calculator gets bigger and bigger, the code gets more complicated. It would be a nightmare if you accidentally moved code elsewhere. And if we want to get a youth version of the calculator from inside it is not convenient to achieve.

In short, simple factories are designed to meet simple needs quickly.

The abstract factory

The idea behind abstract factories is to provide some common method names and then replace a function with a variable.

For example, vue’s renderer provides SSR and DOM renderers, and determines subsequent behavior by specifying which renderer to use. Along similar lines:

    function ssr() {}
    
    function dom() {}
    
    function Renderer(render) {
        this.render = render
        // ...
    }
    
    const render = new Renderer(dom)
    
    render.xxx()
Copy the code

What is the difference between an ordinary factory and an abstract factory? Inside a simple factory are conditional branch statements that return behavior by passing in conditions. Abstract factories weaken the conditional branch statement and pass in the base method directly, returning the encapsulated method with more functionality, and changing the internal logic without changing the external usage.

The strategy pattern

Our policy pattern can be implemented with abstract factories.

Again, let’s use the calculator as an example. Once we’re done, we can compare the advantages of the calculator implementation with a simple factory.

    function add(a, b) {
        return a + b
    }
    
    function minus(a, b) {
        return a - b
    }
    
    // Other calculation methods...
    
    class Calculator {
        constructor(method) {
            this.setMethod(method)
        }
        
        setMethod() {
            this.method = method
        }
        
        compute(a, b) {
            this.method(a, b)
        }
    }
    
    const calculator = new Calculator(add)
    
    calculator.compute(1.2)
Copy the code

Advantages: We only need to identify a method add at initialization, and then we can operate in a uniform form. And we don’t have to change any of the functions we’ve written before. Just change the established method.