ℹ️ This repository is part of my Refactoring catalog based on Fowler's book with the same title. Please see kaiosilveira/refactoring for more details.
Formerly: Replace Constructor with Factory Method
Before | After |
---|---|
leadEngineer = new Employee(document.leadEngineer, 'E'); |
leadEngineer = createEngineer(document.leadEngineer); |
Sometimes we need more control over initialization than a constructor can possibly provide, and that's where a Factory Method comes in handy: it can hide complex initialization logic, replace the resulting instance with a proxy or decorate it with complementary behavior. This refactoring helps with moving towards this approach.
Our working example is a program that creates Employee
instances based on a document input plus employee type. The Employee
class is straightforward:
export class Employee {
constructor(name, typeCode) {
this._name = name;
this._typeCode = typeCode;
}
get name() {
return this._name;
}
get type() {
return Employee.legalTypeCodes[this._typeCode];
}
static get legalTypeCodes() {
return { E: 'Engineer', M: 'Manager', S: 'Salesperson' };
}
}
And some possible usages are:
const candidateDoc = { name: 'John Doe', empType: 'E' };
const candidate = new Employee(candidateDoc.name, candidateDoc.empType);
const leadEngineerDoc = { leadEngineer: 'Jane Doe' };
const leadEngineer = new Employee(leadEngineerDoc.leadEngineer, 'E');
console.log(`Candidate: ${candidate.name}, ${candidate.type}`);
console.log(`Lead engineer: ${leadEngineer.name}, ${leadEngineer.type}`);
Our goal here is to introduce a factory function, so clients don't do new
employees any longer.
Occaecat et incididunt aliquip ex id dolore. Et excepteur et ea aute culpa fugiat consectetur veniam aliqua. Adipisicing amet reprehenderit elit qui.
describe('functionBeingRefactored', () => {
it('should work', () => {
expect(0).toEqual(1);
});
});
Magna ut tempor et ut elit culpa id minim Lorem aliqua laboris aliqua dolor. Irure mollit ad in et enim consequat cillum voluptate et amet esse. Fugiat incididunt ea nulla cupidatat magna enim adipisicing consequat aliquip commodo elit et. Mollit aute irure consequat sunt. Dolor consequat elit voluptate aute duis qui eu do veniam laborum elit quis.
- introduce
createEmployee
function:
diff --git top level...
+export function createEmployee(name, typeCode) {
+ return new Employee(name, typeCode);
+}
- update callers to use
createEmployee
instead of initializing the class themselves:
diff --git top level...
-const candidate = new Employee(candidateDoc.name, candidateDoc.empType);
+const candidate = createEmployee(candidateDoc.name, candidateDoc.empType);
// ...
-const leadEngineer = new Employee(leadEngineerDoc.leadEngineer, 'E');
+const leadEngineer = createEmployee(leadEngineerDoc.leadEngineer, 'E');
- rename
createEmployee
tocreateEngineer
:
diff --git top level...
-const candidate = createEmployee(candidateDoc.name, candidateDoc.empType);
+const candidate = createEngineer(candidateDoc.name, candidateDoc.empType);
// ...
-const leadEngineer = createEmployee(leadEngineerDoc.leadEngineer, 'E');
+const leadEngineer = createEngineer(leadEngineerDoc.leadEngineer, 'E');
// ...
-export function createEmployee(name, typeCode) {
+export function createEngineer(name, typeCode) {
- make employee type fixed to
'E'
atcreateEngineer
:
diff --git top level...
export function createEngineer(name, typeCode) {
- return new Employee(name, typeCode);
+ return new Employee(name, 'E');
- remove
typeCode
argument fromcreateEngineer
:
diff --git top level...
-export function createEngineer(name, typeCode) {
+export function createEngineer(name) {
And that's it!
Below there's the commit history for the steps detailed above.
Commit SHA | Message |
---|---|
3ff0ba7 | introduce createEmployee function |
75b2e05 | update callers to use createEmployee instead of initializing the class themselves |
e48639d | rename createEmployee to createEngineer |
9886939 | make employee type fixed to 'E' at createEngineer |
b15df82 | remove typeCode argument from createEngineer |
For the full commit history for this project, check the Commit History tab.