Skip to content

Working example with detailed commit history on the "replace constructor with factory function" refactoring based on Fowler's "Refactoring" book

License

Notifications You must be signed in to change notification settings

kaiosilveira/replace-constructor-with-factory-function-refactoring

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Continuous Integration

ℹ️ This repository is part of my Refactoring catalog based on Fowler's book with the same title. Please see kaiosilveira/refactoring for more details.


Replace Constructor With Factory Function

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.

Working example

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.

Test suite

Since we're doing with a simple class, there is no test suite in place. Tests will be introduced as we go, though, for the createEmployee factory function.

Steps

We start by introducing the createEmployee function:

diff --git top level...
+export function createEmployee(name, typeCode) {
+  return new Employee(name, typeCode);
+}

Then, we update the callers to use the function 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');

With that in place, and since we're only creating engineer employees, a decision was made to make the function more specific. We start by renaming createEmployee to createEngineer:

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) {

And then, we make the employee type fixed to 'E' at createEngineer:

diff --git top level...
 export function createEngineer(name, typeCode) {
-  return new Employee(name, typeCode);
+  return new Employee(name, 'E');

Finally, we can remove the flag argument typeCode from createEngineer:

diff --git top level...
-export function createEngineer(name, typeCode) {
+export function createEngineer(name) {

And that's it!

Commit history

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.

About

Working example with detailed commit history on the "replace constructor with factory function" refactoring based on Fowler's "Refactoring" book

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

No packages published