ℹ️ This repository is part of my Refactoring catalog based on Fowler's book with the same title. Please see kaiosilveira/refactoring for more details.
Before | After |
---|---|
manager = aPerson.department.manager; |
manager = aPerson.manager;
class Person {
get manager() {
return this._department.manager;
}
// ...
} |
Inverse of: Remove middle man
Encapsulation is at the roots of good code design, it helps in keeping coupling low by hiding the internal details of a given class/module, which allows for better and safer refactorings, freedom for exploring new ideas (which eventually leads to deeper, more supple domain models). This refactoring sheds some light on how to hide our delegates, therefore keeping our data encapsulated.
Our working example is simple and straightforward: we have a Person
class that contains some department
info. The info related to a person's manager is inside the department
reference, but that'd be great if we could hide the implementation details from the clients.
A supporting test suite was added to make sure none of our refactoring steps introduced any errors. It covers the client code resolving the manager
info of a given person
.
describe('getManager', () => {
it('should fetch the manager of a person', () => {
const department = new Department();
department.chargeCode = '123';
department.manager = 'Martin';
const aPerson = new Person({ name: 'Kaio' });
aPerson.department = department;
expect(getManager(aPerson)).toEqual('Martin');
});
});
We start by adding a manager
getter to Person
:
diff --git a/src/Person.js b/src/Person.js
@@ -14,5 +14,8 @@
export class Person {
set department(arg) {
this._department = arg;
}
-}
+ get manager() {
+ return this._department.manager;
+ }
+}
Then, we can simply update our callers to read the manager
info directly from Person
instead of accessing its department
:
diff --git a/src/client/index.js b/src/client/index.js
@@ -1,4 +1,4 @@
export function getManager(aPerson) {
- const manager = aPerson.department.manager;
+ const manager = aPerson.manager;
return manager;
}
And that's it, as simple as that! In a real-world scenario, though, this could be a gradual process where we update caller by caller at a varying pace. The code would remain functional until we eventually finish updating all callers and remove the department
getter completely:
diff --git a/src/Person.js b/src/Person.js
@@ -7,10 +7,6 @@
export class Person {
return this._name;
}
- get department() {
- return this._department;
- }
-
set department(arg) {
this._department = arg;
}
Below there's the commit history for the steps detailed above.
Commit SHA | Message |
---|---|
872871b | add a get to manager at Person |
d1c4386 | update Person clients to read manager prop directly from it |
a4f2280 | remove department getter at Person |
For the full commit history for this project, check the Commit History tab.