Created
March 25, 2022 20:59
-
-
Save mheiber/b21cad62e6745160101d045f34d54dff to your computer and use it in GitHub Desktop.
A Refactor Most Fowl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// From "Refactoring" 2nd Edition by Martin Fowler | |
export default function createStatementData(invoice, plays) { | |
const result = {}; | |
result.customer = invoice.customer; | |
result.performances = invoice.performances.map(enrichPerformance); | |
result.totalAmount = totalAmount(result); | |
result.totalVolumeCredits = totalVolumeCredits(result); | |
return result; | |
function enrichPerformance(aPerformance) { | |
const calculator = createPerformanceCalculator(aPerformance, playFor(aPerformance)); | |
const result = Object.assign({}, aPerformance); | |
result.play = calculator.play; | |
result.amount = calculator.amount; | |
result.volumeCredits = calculator.volumeCredits; | |
return result; | |
} | |
function playFor(aPerformance) { | |
return plays[aPerformance.playID] | |
} | |
function totalAmount(data) { | |
return data.performances.reduce((total, p) => total + p.amount, 0); | |
} | |
function totalVolumeCredits(data) { | |
return data.performances | |
.reduce((total, p) => total + p.volumeCredits, 0); | |
} | |
function createPerformanceCalculator(aPerformance, aPlay) { | |
switch(aPlay.type) { | |
case "tragedy": return new TragedyCalculator(aPerformance, aPlay); | |
case "comedy" : return new ComedyCalculator(aPerformance, aPlay); | |
default: | |
throw new Error(`unknown type: ${aPlay.type}`); | |
} | |
} | |
class PerformanceCalculator { | |
constructor(aPerformance, aPlay) { | |
this.performance = aPerformance; | |
this.play = aPlay; | |
} | |
get amount() { | |
throw new Error('subclass responsibility'); | |
} | |
get volumeCredits() { | |
return Math.max(this.performance.audience - 30, 0); | |
} | |
} | |
class TragedyCalculator extends PerformanceCalculator { | |
get amount() { | |
let result = 40000; | |
if (this.performance.audience > 30) { | |
result += 1000 * (this.performance.audience 30) | |
} | |
return result; | |
} | |
} | |
class ComedyCalculator extends PerformanceCalculator { | |
get amount() { | |
let result = 30000; | |
if (this.performance.audience > 20) { | |
result += 10000 + 500 * (this.performance.audience 20) | |
} | |
result += 300 * this.performance.audience; | |
return result; | |
} | |
get volumeCredits() { | |
return super.volumeCredits + Math.floor(this.performance.audience / 5) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment