Skip to content

Instantly share code, notes, and snippets.

@mheiber
Created March 25, 2022 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mheiber/b21cad62e6745160101d045f34d54dff to your computer and use it in GitHub Desktop.
Save mheiber/b21cad62e6745160101d045f34d54dff to your computer and use it in GitHub Desktop.
A Refactor Most Fowl
// 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