The Factory Method pattern belongs to the group of creational design patterns. Its main purpose is to create configurable objects based on given data.
đź“• Vocabulary: In object-oriented programming a factory is a regular function that returns a new instance of an object and doesn’t need the
newkeyword.
Javascript implementation
in concrete, it is useful when you need to create an object with different configurations. For example, let’s think about instantiating a widget with different data for different environments.
// Factory function
const createWidget = ({ apiKey, secretKey, environment = 'production' }) => ({
apiKey,
secretKey,
environment,
run() {
return `start ${this.environment} with key ${this.apiKey}`;
}
});
const productionWidget = createWidget({
apiKey: 'productionApiKey',
secretKey: 'productionSecretKey',
});
const stagingWidget = createWidget({
apiKey: 'developApiKey',
secretKey: 'developSecretKey',
environment: 'staging'
});
productionWidget.run()
stagingWidget.run()
Typescript implementation
In typescript, we can also have an additional level of abstraction using an abstract function
// Widget Interface
interface Widget {
apiKey: string;
secretKey: string;
environment: 'production' | 'staging';
run(): string;
}
// Abstract factory function
function createAbstractWidget(config: {
apiKey: string;
secretKey: string;
environment?: 'production' | 'staging';
}): Widget {
if (!config.apiKey || !config.secretKey) {
throw new Error('Missing required parameters: apiKey and secretKey');
}
return {
apiKey: config.apiKey,
secretKey: config.secretKey,
environment: config.environment || 'production',
run() {
return `start ${this.environment} with key ${this.apiKey}`;
},
};
}
// Concrete factory functions
function createProductionWidget(): Widget {
return createAbstractWidget({
apiKey: 'productionApiKey',
secretKey: 'productionSecretKey',
});
}
function createStagingWidget(): Widget {
return createAbstractWidget({
apiKey: 'developApiKey',
secretKey: 'developSecretKey',
environment: 'staging',
});
}
const productionWidget = createProductionWidget();
const stagingWidget = createStagingWidget();
productionWidget.run()
stagingWidget.run()
Wrapping up
In the most classical implementation, the pattern factory method makes use of three entities:
- The factory: Responsible for creating a new object
- Abstract function: (Only TypeScript) The interface of the object
- Concrete function: Creates the effective object
Disavantages
For me, the most well-founded criticism of this pattern in javascript is that it violates the open–closed principle (OCP), which is that in software engineering a system should be open for extension but closed for change.