import INVOICE from "../invoices.json";
import PLAYS from "../plays.json";
function statement(invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `์ฒญ๊ตฌ ๋ด์ญ(๊ณ ๊ฐ๋ช
: ${invoice.customer})\n`;
const format = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format;
for (let perf of invoice.performances) {
const play = plays[perf.playID]; // object {name, type}
let thisAmount = 0;
switch (play.type) {
case "tragedy": //๋น๊ทน
thisAmount = 40000;
if (perf.audience > 30) thisAmount += 1000 * (perf.audience - 30);
break;
case "comedy": //ํฌ๊ทน
thisAmount = 30000;
if (perf.audience > 20) thisAmount += 1000 + 500 * (perf.audience - 20);
thisAmount += 300 * perf.audience;
break;
default:
throw new Error(`์ ์ ์๋ ์ฅ๋ฅด: ${play.type}`);
}
// ํฌ์ธํธ๋ฅผ ์ ๋ฆฝํ๋ค.
volumeCredits += Math.max(perf.audience - 30, 0);
// ํฌ๊ทน ๊ด๊ฐ 5๋ช
๋ง๋ค ์ถ๊ฐ ํฌ์ธํธ๋ฅผ ์ ๊ณตํ๋ค.
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
// ์ฒญ๊ตฌ ๋ด์ญ์ ์ถ๋ ฅํ๋ค.
result += `${play.name}: ${format(thisAmount / 100)} (${
perf.audience
}์)\n`;
totalAmount += thisAmount;
}
result += `์ด์ก: ${format(totalAmount / 100)}\n`;
result += `์ ๋ฆฝ ํฌ์ธํธ: ${volumeCredits}์ \n`;
return result;
}
statement(INVOICE[0], PLAYS);
-
์ด ์ฝ๋ ์์ฒด๋ก๋, ํ๋ก๊ทธ๋จ์ด ์งง์ ํน๋ณํ ์ ์จ ์ดํดํด์ผ ํ ๊ตฌ์กฐ๊ฐ ์๋ค.
-
ํ์ง๋ง, ์ด๋ฐ ์ฝ๋๊ฐ ์๋ฐฑ ์ค ์ง๋ฆฌ์ ํ๋ก๊ทธ๋จ์ ์ผ๋ถ๋ผ๋ฉด ๊ฐ๋จํ ์ธ๋ผ์ธ ํจ์ ํ๋๋ผ๋ ์ดํดํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค.
-
ํ๋ก๊ทธ๋จ์ด ์ ์๋ํ๋ ์ํฉ์์, ๊ทธ์ ์ฝ๋๊ฐ '์ง์ ๋ถํ๋ค' ํ๋ค๊ณ ๋ถํํ๋ ๊ฒ์ ํ๋ก๊ทธ๋จ์ ๊ตฌ์กฐ๋ฅผ ์ง๋์น๊ฒ ๋ฏธ์ ์ธ ๊ธฐ์ค์ผ๋ก ํ๋จํ๋ค๋ ์๊ฒฌ๋ ์์ ์ ์์ง๋ง, ์ฝ๋๋ฅผ ์์ ํ๋ ค๋ฉด ์ฌ๋์ด ๊ฐ์ ๋๊ณ ๋ ์ฌ๋์ ์ฝ๋์ ๋ฏธ์ ์ํ์ ๋ฏผ๊ฐํ๋ค.
์ฆ ์ค๊ณ๊ฐ ๋์ ์์คํ ์ ์์ ํ๊ธฐ ์ด๋ ต๋ค. -> ์ํ๋ ๋์์ ์ํํ๋๋ก ํ๊ธฐ ์ํ์ฌ ์์ ํด์ผ ํ ๋ถ๋ถ์ ์ฐพ๊ณ , ๊ธฐ์กด ์ฝ๋์ ์ ๋ง๋ฌผ๋ ค ์๋ํ๊ฒ ํ ๋ฐฉ๋ฒ์ ์ฐพ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ด๋ค. ์ค์์ ๋ฒ๊ทธ์ ๋ฐ์ ๊ฐ๋ฅ์ฑ ์ญ์ ๋์์ง๋ค.
๋จผ์ ํ๋ก๊ทธ๋จ์ ์๋ ๋ฐฉ์์ ์ ํ์ ํ ์ ์๋๋ก ์ฝ๋๋ฅผ ์ฌ๋ฌ ํจ์์ ํ๋ก๊ทธ๋จ ์์๋ก ์ฌ๊ตฌ์ฑํด์ผํ๋ค. ํ๋ก๊ทธ๋จ์ ๊ตฌ์กฐ๊ฐ ๋น์ฝํ๋ค๋ฉด, ๋์ฒด๋ก ๊ตฌ์กฐ๋ถํฐ ๋ฐ๋ก์ก์์ผ ์์ ์ด ์์ํด์ง๋ค.
- ์ฒญ๊ตฌ ๋ด์ญ์ HTML๋ก ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ
- ์ฒญ๊ตฌ ๊ฒฐ๊ณผ์ ๋ฌธ์์ด์ ์ถ๊ฐํ๋ ๋ฌธ์ฅ ๊ฐ๊ฐ์ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๊ฐ์ธ์ผํจ
- ์ด ๊ฒฝ์ฐ ๋๋ถ๋ถ ์ด ํจ์์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด ๋ณต์ฌ๋ณธ์์ HTML์ ์ถ๋ ฅํ๋ ์์ผ๋ก ์ฒ๋ฆฌ
- ์ฒญ๊ตฌ์ ์์ฑ ๋ก์ง์ด ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค ๊ธฐ์กด ํจ์์ HTML ๋ฒ์ ํจ์ ๋ชจ๋ ์์ , ํญ์ ์ผ๊ด๋๊ฒ ์์ ํ๋์ง ์ญ์ ํ์ธ
- ๋ฐฐ์ฐ๋ค์ ๋ ๋ง์ ์ฅ๋ฅด๋ฅผ ์ฐ๊ธฐํ๊ณ ์ถ์ด ํ๋๋ฐ, ์ด๋ฌํ ๋ณ๊ฒฝ์ ๊ณต์ฐ๋ฃ์ ์ ๋ฆฝ ํฌ์ธํธ ๊ณ์ฐ๋ฒ์ ์ํฅ์ ์ค๋ค. ๋ฐ๋ผ์ ์ฐ๊ทน ์ฅ๋ฅด์ ๊ณต์ฐ๋ฃ ์ ์ฑ ์ด ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค statement() ํจ์๋ฅผ ์์ ํด์ผ ํ๋๋ฐ, ์ด๋ฅผ ๋ณต์ฌํด์ htmlStatement()๋ฅผ ๋ง๋ ๋ค๋ฉด ๋ชจ๋ ์์ ์ด ๋ ํจ์ ๊ฐ๊ฐ์ ์ผ๊ด์ฑ์ ๊ฐ์ ธ์ผํ๋ค.
์์ ๊ฐ์ด ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์ํ ๋ ์ค์๋ฅผ ์ค์ผ ์ ์๋ค
๋ฆฌํฉํฐ๋ง์์ ํ ์คํธ์ ์ญํ ์ ๊ต์ฅํ ์ค์ํ๋ค. ๋ฆฌํฉํฐ๋ง ํ๊ธฐ ์ ์ ์ ๋๋ก ๋ ํ ์คํธ ๋ถํฐ ๋ง๋ จํ๊ณ , ํ ์คํธ๋ ๋ฐ๋์ ์๊ฐ์ง๋จ์ด ๊ฐ๋ฅํด์ผํ๋ค. ์ํ๋ ๋ด์ฉ์ ์์ค์ฝ๋์ ํ ์คํธ ์ฝ๋ ์์ชฝ์ ์ ์ด๋๋ฉด ๋ ๋ฒ ๋ค ๋๊ฐ์ด ์ค์ํ์ง ์๋ ํ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ด๋ค. ํ ์คํธ ์์ฑ ์ ์๊ฐ์ด ๊ฑธ๋ฆด์ง๋ผ๋ ์ ๊ฒฝ ์จ์ ๋ง๋ค์ด๋๋ฉด ๋๋ฒ๊น ์๊ฐ์ด ๊ฐ์ํ๋ค.
๋ฆฌํฉํฐ๋ง ์ ์์ ๋จ๊ณ๋ก ๋๋์ด ์งํํด์ผํ๋ค. ์ค๊ฐ์ ์ค์ํ๋๋ผ๋ ๋ฒ๊ทธ๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
import INVOICE from "../../invoices.json";
import PLAYS from "../../plays.json";
function statement(invoice, plays) {
let result = `์ฒญ๊ตฌ ๋ด์ญ(๊ณ ๊ฐ๋ช
: ${invoice.customer})\n`;
for (let perf of invoice.performances) {
// ์ฒญ๊ตฌ ๋ด์ญ์ ์ถ๋ ฅํ๋ค.
result += `${playFor(perf).name}: ${usd(amountFor(perf))} (${
perf.audience
}์)\n`;
}
result += `์ด์ก: ${usd(totalAmount())}\n`;
result += `์ ๋ฆฝ ํฌ์ธํธ: ${totalVolumeCredits()}์ \n`;
return result;
function usd(aNumber) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format(aNumber / 100);
}
function volumeCreditsFor(aPerformance) {
let result = 0;
result += Math.max(aPerformance.audience - 30, 0);
if ("comedy" === playFor(aPerformance).type)
result += Math.floor(aPerformance.audience / 5);
return result;
}
function totalVolumeCredits() {
let volumeCredits = 0;
for (let perf of invoice.performances) {
volumeCredits += volumeCreditsFor(perf);
}
return volumeCredits;
}
function totalAmount() {
let result = 0;
for (let perf of invoice.performances) {
result += amountFor(perf);
}
return result;
}
function playFor(aPerformance) {
return plays[aPerformance.playID];
}
// play๋ aPerformance์์ ์ค๋ ๊ฐ์ด๋ผ์ ์ ๊ฑฐ
function amountFor(aPerformance) {
let result = 0;
switch (playFor(aPerformance).type) {
case "tragedy": //๋น๊ทน
result = 40000;
if (aPerformance.audience > 30)
result += 1000 * (aPerformance.audience - 30);
break;
case "comedy": //ํฌ๊ทน
result = 30000;
if (aPerformance.audience > 20)
result += 1000 + 500 * (aPerformance.audience - 20);
result += 300 * aPerformance.audience;
break;
default:
throw new Error(`์ ์ ์๋ ์ฅ๋ฅด: ${playFor(aPerformance).type}`);
}
return result;
}
}
console.log(statement(INVOICE[0], PLAYS));
- ํจ์ ์ถ์ถ
- ๋ณ์๋ช ๋ณ๊ฒฝ
- ๋ณ์ ์ธ๋ผ์ธ์ผ๋ก ๋ณ๊ฒฝ
- ๋ฐ๋ณต๋ฌธ ์ชผ๊ฐ๊ธฐ
- ์ ๋์ด๋ก ํ์ ํํํ๊ธฐ
- ๋งค๊ฐ๋ณ์์ ํ์ ์ด ๋๋ ทํ์ง ์์ ๋ ๋ถ์ ๊ด์ฌ(a/an) ๋ถ์ด๊ธฐ
- ์บํธ๋ฐฑ ์ฐธ๊ณ
์ข์ ์ฝ๋๋ ํ๋์ผ์ด ๋ช ํํ๊ฒ ๋๋ฌ๋๋ ์ฝ๋์ด๊ณ , ๋ณ์ ์ด๋ฆ์ ์ด์ ํฐ ์ญํ ์ ํ๋ค.
- ๋ค์๋ฒ์ ์ฝ๋๋ฅผ ๋ณผ ๋ ๋ค์ ๋ถ์ํ์ง ์์๋, ์ฝ๋ ์์ฒด๋ง ๋ณด๊ณ ๋ ๋ฌด์์ ํ๋ ๊ฒ์ธ์ง ์ดํดํ ์ ์์ด์ผ ํ๋ค.
- ์์๋ณ์๋ฅผ ์ง์ํจ์๋ก ๋ฐ๊พธ์
- ๊ธด ํจ์๋ฅผ ์ชผ๊ฐค ๋ ๋ง๋ค ๋ณ์๋ฅผ ์ต๋ํ ์ ๊ฑฐํ๋ค.
- ์ง์ญ ๋ณ์๋ฅผ ์ ๊ฑฐํ๋ฉด ์ถ์ถ ์์ ์ด ํจ์ฌ ์ฌ์์ง๋ค๋ ์ฅ์ ์ด ์๋ค. (์ ํจ๋ฒ์ ์ ๊ฒฝ์ ์ฐ์ง ์์๋ ๋จ)
- ๋ณ์ ์ธ๋ผ์ธํ๊ธฐ
- ํจ์๋ช ๋ฐ๊พธ๊ธฐ ์ธ๋ผ์ธํ๊ธฐ
- ์ด๋ฆ์ง๊ธฐ๋ ์ค์ํ๋ฉด์๋ ์ฝ์ง ์์ ์์ ์ด๋ค.
- ์ด๋ฆ์ด ์ข์ผ๋ฉด ํจ์ ๋ณธ๋ฌธ์ ์ฝ์ง ์์๋ ๋ฌด์จ ์ผ์ ํ๋์ง ์ ์ ์๋ค.
- ๋ฌธ์ฅ ์ฌ๋ผ์ด๋ํ๊ธฐ
import INVOICE from "../../invoices.json";
import PLAYS from "../../plays.json";
import createStatementData from "./createStatementData.js";
function statement(invoice, plays) {
// ๊ฐ๋ณ๋ฐ์ดํฐ๋ก ๋๊ธฐ๋ฉด ๊ธ๋ฐฉ ์ํ๊ธฐ๋๋ฌธ์ ์ต๋ํ ๋ถ๋ณ์ผ๋ก ๋๊ธด๋ค. (๊ตฟ)
return renderPlainText(createStatementData(invoice, plays));
}
function renderPlainText(data, plays) {
let result = `์ฒญ๊ตฌ ๋ด์ญ(๊ณ ๊ฐ๋ช
: ${data.customer})\n`;
for (let perf of data.performances) {
// ์ฒญ๊ตฌ ๋ด์ญ์ ์ถ๋ ฅํ๋ค.
result += `${perf.play.name}: ${usd(perf.amount)} (${perf.audience}์)\n`;
}
result += `์ด์ก: ${usd(data.totalAmount)}\n`;
result += `์ ๋ฆฝ ํฌ์ธํธ: ${data.totalVolumeCredits}์ \n`;
return result;
}
function htmlStatement(invoice, plays) {
return renderHtml(createStatementData(invoice, plays));
}
function renderHtml(data) {
let result = `<h1>์ฒญ๊ตฌ ๋ด์ญ(๊ณ ๊ฐ๋ช
: ${data.customer})</h1>\n`;
result += `<table>\n`;
result += `<tr><th>์ฐ๊ทน</th><th>์ข์ ์</th><th>๊ธ์ก</th></tr>`;
for (let perf of data.performances) {
// ์ฒญ๊ตฌ ๋ด์ญ์ ์ถ๋ ฅํ๋ค.
result += `<tr><td>${perf.play.name}</td><td>(${perf.audience}์)</td>`;
result += `<td>${usd(perf.amount)}</td></tr>\n`;
}
result += `</table>\n`;
result += `์ด์ก: ${usd(data.totalAmount)}\n`;
result += `์ ๋ฆฝ ํฌ์ธํธ: ${data.totalVolumeCredits}์ \n`;
return result;
}
function usd(aNumber) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format(aNumber / 100);
}
document.getElementById("app2").innerText = statement(INVOICE[0], PLAYS);
document.getElementById("app").innerHTML = htmlStatement(INVOICE[0], PLAYS);
- ๋จ๊ณ ์ชผ๊ฐ๊ธฐ
- ํจ์ ์ฎ๊ธฐ๊ธฐ
- ๋ฐ๋ณต๋ฌธ -> ํ์ดํ๋ผ์ธ
- ๊ฐ๊ฒฐํจ ๋ณด๋จ ๋ช ๋ฃํจ์ด ์ค์ํ๋ค. ํ๋ก๊ทธ๋๋ฐ์์๋ ๋ช ๋ฃํจ์ด ์งํํ ์ ์๋ ์ํํธ์จ์ด์ ์ ์๋ค.
์ข์ ์ฝ๋๋ฅผ ๊ฐ๋ ํ๋ ๊ฐ์ฅ ํ์คํ ๋ฐฉ๋ฒ์ ์ผ๋ง๋ ์์ ํ๊ธฐ ์ฌ์ด๊ฐ
์ด๋ค.
class PerformanceCalculator {
constructor(aPerformance, aPlay) {
this.performance = aPerformance;
this.play = aPlay;
}
get amount() {
throw new Error("์๋ธํด๋์ค์์ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณ");
}
get volumeCredits() {
throw new Error("์๋ธํด๋์ค์์ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณ");
}
}
class TragedyCalculator extends PerformanceCalculator {
get amount() {
let result = 40000;
if (this.performance.audience > 30)
result += 1000 * (this.performance.audience - 30);
return result;
}
get volumeCredits() {
return Math.max(this.performance.audience - 30, 0);
}
}
class ComedyCalculator extends PerformanceCalculator {
get amount() {
let result = 30000;
if (this.performance.audience > 20)
result += 1000 + 500 * (this.performance.audience - 20);
result += 300 * this.performance.audience;
return result;
}
get volumeCredits() {
return Math.floor(this.performance.audience / 5);
}
}
export default function createStatementData(invoice, plays) {
const statementData = {};
statementData.customer = invoice.customer; // ๊ณ ๊ฐ๋ฐ์ดํฐ๋ฅผ ์ค๊ฐ ๋ฐ์ดํฐ๋ก ์ฎ๊น
statementData.performances = invoice.performances.map(enrichPerformance);
statementData.totalAmount = totalAmount(statementData);
statementData.totalVolumeCredits = totalVolumeCredits(statementData);
return statementData;
function enrichPerformance(aPerformance) {
// ๊ฐ๊ฐ ๊ณต์ฐ๋ณ๋ก ์ด๋ฆ, ์ด๊ธ์ก, ์ดํฌ์ธํธ๋ค์ ์๋กํ ๋น
const calculator = createPerformanceCalculator(
aPerformance,
playFor(aPerformance)
);
const result = Object.assign({}, aPerformance);
result.play = playFor(result);
result.amount = calculator.amount;
result.volumeCredits = calculator.volumeCredits;
return result; // ์์๋ณต์ฌ
}
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(`์ ์ ์๋ ์ฅ๋ฅด: ${aPlay.type}`);
}
}
// ํ์
(tragedy, comedy)
function playFor(aPerformance) {
return plays[aPerformance.playID];
}
function totalVolumeCredits(data) {
return data.performances.reduce((total, p) => total + p.volumeCredits, 0);
}
function totalAmount(data) {
return data.performances.reduce((total, p) => total + p.amount, 0);
}
}
์กฐ๊ฑด๋ถ ๋ก์ง์ ๋คํ์ฑ์ผ๋ก ๋ณ๊ฒฝํ์
- ์ฝ๋๋ ๋ช ํํด์ผํ๊ณ
- ์ฝ๋๋ฅผ ์์ ํด์ผํ ์ํฉ์ด ๋๋ฉด ๊ณ ์ณ์ผ ํ ๊ณณ์ ์ฝ๊ฒ ์ฐพ์ ์ ์๊ณ , ์ค๋ฅ๊ฐ ์์ด ๋น ๋ฅธ ์์ ์ด ๊ฐ๋ฅํด์ผํ๋ค.
- ๊ฑด๊ฐํ ์ฝ๋๋ฒ ์ด์ค๋ ์์ฐ์ฑ์ ๊ทน๋ํํ๋ค.