C
C
carcw2020-02-07 10:25:57
Design patterns
carcw, 2020-02-07 10:25:57

How to use the strategy design pattern correctly?

I'm trying to apply the "Strategy" pattern, but there are 2 points in which I'm not sure how to do it right.

I have a FormBuilder class (uses to build a form) that uses one of the available strategies to build a form. The strategy is determined based on the input parameters that are passed to the FormBuilder.

There are 2 questions:

  1. Is it correct to implement the strategy selection inside the FormBuilder class, or should the strategy selection and setting be done outside?
  2. Doesn't the code in the example below violate the "Closed for modification, open for extension" principle? If I need to add a new strategy or remove an existing one, I will always have to edit the FormBuilder class as well.


class Form {
    // Данные формы
}

interface IFormStrategy {
    execute(params: object): Form;
}

class SimpleFormStrategy implements IFormStrategy {
    public execute(params: object): Form {
        // Здесь должна быть логика построения простой формы
        return new Form();
    }
}

class ExtendedFormStrategy implements IFormStrategy {
    public execute(params: object): Form {
        // Здесь должна быть логика построения расширенной формы
        return new Form();
    }
}

class CustomFormStrategy implements IFormStrategy {
    public execute(params: object): Form {
        // Здесь должна быть логика построения кастомной формы
        return new Form();
    }
}

class FormBuilder {
    public build(params: object): Form {
        let strategy: IFormStrategy;

        // В этом месте осуществляется выбор стратегии исходя из параметра params

        // Если должна быть простая форма
        strategy = new SimpleFormStrategy();
        // Если должна быть расширенная форма
        strategy = new ExtendedFormStrategy();
        // Если должна быть кастомная форма
        strategy = new CustomFormStrategy();

        return strategy.execute(params);
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Aetae, 2020-02-08
@Aetae

If you don’t want to simply pass the strategy class itself as a parameter, then all that remains is to make a jeshmap where the parameter name will be the key, and the strategy class itself will be the value. When adding a new strategy - add it to the map. Conditionally something like this:

class FormBuilder {
    public static strategies: { [key: string]: {new(): IFormStrategy} } = {
        simple: SimpleFormStrategy,
        extended: ExtendedFormStrategy,
    };
    public build(params: { strategy: string }): Form {
        let strategy: IFormStrategy = new FormBuilder.strategies[params.strategy]();
        return strategy.execute(params);
    }
}

FormBuilder.strategies.custom = CustomFormStrategy;

const formBuilder = new FormBuilder();
formBuilder.build({ strategy: 'custosm' });

Of course, the map can be made private and added using a public method. Or store it separately. We also need to check that such a strategy exists at all, but these are all details ...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question