重構之前的程式碼
<?php
/**
* Created by PhpStorm.
* User: Monkey
* Date: 2019-08-27
* Time: 22:57
*/
$playsStr = '{
"hamlet": {"name": "Hamlet", "type": "tragedy"},
"as-like": {"name": "As You Like It", "type": "comedy"},
"othello": {"name": "Othello", "type": "tragedy"}
}';
$invoicesStr =
'[
{
"customer": "BigCo",
"performances": [
{
"playID": "hamlet",
"audience": 55
},
{
"playID": "as-like",
"audience": 35
},
{
"playID": "othello",
"audience": 40
}
]
}
]';
$plays = json_decode($playsStr, true);
$invoices = json_decode($invoicesStr, true);
/**
* @param $invoices
* @param $plays
* @return string
*/
function statement($invoices, $plays)
{
$totalAmount = 0;
$volumeCredits = 0;
$result = "Statement for {$invoices[0]['customer']} " . PHP_EOL;
$perf = $invoices[0]['performances'];
foreach ($perf as $key => $value) {
$thisAmount = 0;
switch ($plays[$value['playID']]['type']) {
case 'tragedy' :
$thisAmount = 40000;
if ($value['audience'] > 30) {
$thisAmount += 1000 * ($value['audience'] - 30);
}
break;
case 'comedy' :
$thisAmount = 30000;
if ($value['audience'] > 20) {
$thisAmount += 10000 + 500 * ($value['audience'] - 20);
}
$thisAmount += 300 * $value['audience'];
break;
default:
echo("unknown type: {$plays[$value['playID']]['type']}");
}
// add volume credits
$volumeCredits += max($value['audience'] - 30, 0);
// add extra credit for every ten comedy attendees”
if ("comedy" === $plays[$value['playID']]['type']) {
$volumeCredits += floor($value['audience'] / 5);
}
// print line for this order
$result .= " {" . $plays[$value['playID']]['name'] . "}:\$" . number_format($thisAmount / 100) . " ({$value['audience']} seats)" . PHP_EOL;
$totalAmount += $thisAmount;
}
$result .= "Amount owed is \$" . number_format($totalAmount / 100) . PHP_EOL;
$result .= "You earned {$volumeCredits} credits" . PHP_EOL;
return $result;
}
echo statement($invoices, $plays);
重構後
<?php
class Show
{
/**
* @var
*/
public $plays;
/**
* @var
*/
public $invoices;
/**
* Show constructor.
* @param $invoices
* @param $plays
*/
public function __construct($invoices, $plays)
{
$this->invoices = $invoices;
$this->plays = $plays;
}
/**
* @return string
*/
public function statement()
{
$result = "Statement for {$this->invoices[0]['customer']} " . "<br />";
$perf = $this->invoices[0]['performances'];
foreach ($perf as $key => $value) {
$result .= $this->playFor($value)['name'] . " :\$" . $this->usd($this->amountFor($value)) . " { ({$value['audience']} seats) } ," . "<br />";
}
$result .= "Amount owed is \$" . $this->usd($this->totalAmount()) . "<br />";
$result .= "You earned {$this->totalVolumeCredits()} credits" . "<br />";
return $result;
}
/**
* @return float|int|mixed
*/
public function totalVolumeCredits()
{
$result = 0;
foreach ($this->invoices[0]['performances'] as $item => $val) {
$result += $this->volumeCreditsFor($val);
}
return $result;
}
/**
* @param $number
* @return string
*/
public function usd($number)
{
return number_format($number / 100);
}
/**
* @param $value
* @return float|int|mixed
*/
public function volumeCreditsFor($value)
{
$result = 0;
$result += max($value['audience'] - 30, 0);
if ("comedy" === $this->playFor($value)['type']) {
$result += floor($value['audience'] / 5);
}
return $result;
}
/**
* @param $value
* @return float|int
*/
public function amountFor($value)
{
$result = 0;
switch ($this->playFor($value)['type']) {
case 'tragedy' :
$result = 40000;
if ($value['audience'] > 30) {
$result += 1000 * ($value['audience'] - 30);
}
break;
case 'comedy' :
$result = 30000;
if ($value['audience'] > 20) {
$result += 10000 + 500 * ($value['audience'] - 20);
}
$result += 300 * $value['audience'];
break;
default:
echo("unknown type: {$this->playFor($value)['type']}");
}
return $result;
}
/**
* @param $value
* @return mixed
*/
public function playFor($value)
{
return $this->plays[$value['playID']];
}
/**
* @return float|int
*/
private function totalAmount()
{
$result = 0;
foreach ($this->invoices[0]['performances'] as $key => $value) {
$result += $this->amountFor($value);
}
return $result;
}
}
$playsStr = '{
"hamlet": {"name": "Hamlet", "type": "tragedy"},
"as-like": {"name": "As You Like It", "type": "comedy"},
"othello": {"name": "Othello", "type": "tragedy"}
}';
$invoicesStr =
'[
{
"customer": "BigCo",
"performances": [
{
"playID": "hamlet",
"audience": 55
},
{
"playID": "as-like",
"audience": 35
},
{
"playID": "othello",
"audience": 40
}
]
}
]';
$plays = json_decode($playsStr, true);
$invoices = json_decode($invoicesStr, true);
$show = new Show($invoices, $plays);
echo $show->statement();
增加一個新需求:將演出資訊列印到 html 中
<?php
/**
* Created by PhpStorm.
* User: Monkey
* Date: 2019-08-28
* Time: 20:47
*/
class Show
{
/**
* @var
*/
public $plays;
/**
* @var
*/
public $invoices;
/**
* Show constructor.
* @param $invoices
* @param $plays
*/
public function __construct($invoices, $plays)
{
$this->invoices = $invoices;
$this->plays = $plays;
}
/**
* 準備兩個業務需要的資料;
*
* 這樣不同業務只需要關係業務本身,不用關注資料問題;
*
* @return array
*/
public function createStatementData()
{
$result = [];
$result['customer'] = $this->invoices[0]['customer'];
$result['performances'] = $this->getPerformances($this->invoices[0]['performances']);
$result['totalAmount'] = $this->totalAmount($result);
$result['totalVolumeCredits'] = $this->totalVolumeCredits($result);
return $result;
}
/**
* 準備 performances 資料
*
* @param $performanceses
* @return array
*/
public function getPerformances($performanceses)
{
return array_map(function ($result) {
$result['play'] = $this->playFor($result);
$result['amount'] = $this->amountFor($result);
$result['volumeCredits'] = $this->volumeCreditsFor($result);
return $result;
}, $performanceses);
}
/**
* 輸出宣告
*
* @return string
*/
public function statement()
{
return $this->renderPlainText($this->createStatementData());
}
/**
* 列印 html 宣告
*
* @return string
*/
public function renderStatement()
{
return $this->renderHtml($this->createStatementData());
}
/**
* 列印
*
* @param $data
* @return string
*/
public function renderHtml($data)
{
$result = "<h1>Statement for \${" . $data['customer'] . "}</h1>\n";
$result .= "<table>\n";
$result .= "<tr><th>play</th><th>seats</th><th>cost</th></tr>";
foreach ($data['performances'] as $value) {
$result .= " <tr><td>\${" . $value['play']['name'] . "}</td><td>\${" . $value['audience'] . "}</td>";
$result .= "<td>\${" . $this->usd($this->amountFor($value)) . "}</td></tr>\n";
}
$result .= "</table>\n";
$result .= "<p>Amount owed is <em>\${" . $this->usd($data['totalAmount']) . "}</em></p>\n";
$result .= "<p>You earned <em>\${" . $data['totalVolumeCredits'] . "}</em> credits</p>\n";
return $result;
}
/**
* 輸出
*
* @param $statementData
* @return string
*/
public function renderPlainText($statementData)
{
$result = "Statement for {$this->invoices[0]['customer']} <br />" ;
foreach ($statementData['performances'] as $key => $value) {
$result .= $value['play']['name'] . " :\$" . $this->usd($this->amountFor($value)) . " { ({$value['audience']} seats) } ," . "<br />";
}
$result .= "Amount owed is \$" . $this->usd($this->totalAmount($statementData)) . "<br />";
$result .= "You earned {$this->totalVolumeCredits($statementData)} credits" . "<br />";
return $result;
}
/**
* 總積分
*
* @param $statementData
* @return float|int|mixed
*/
public function totalVolumeCredits($statementData)
{
$result = 0;
foreach ($statementData['performances'] as $item => $val) {
$result += $this->volumeCreditsFor($val);
}
return $result;
}
/**
* 格式化金額
*
* @param $number
* @return string
*/
public function usd($number)
{
return number_format($number / 100);
}
/**
* 積分
*
* @param $value
* @return float|int|mixed
*/
public function volumeCreditsFor($value)
{
$result = 0;
$result += max($value['audience'] - 30, 0);
if ("comedy" === $this->playFor($value)['type']) {
$result += floor($value['audience'] / 5);
}
return $result;
}
/**
* 金額
*
* @param $value
* @return float|int
*/
public function amountFor($value)
{
$result = 0;
switch ($this->playFor($value)['type']) {
case 'tragedy' :
$result = 40000;
if ($value['audience'] > 30) {
$result += 1000 * ($value['audience'] - 30);
}
break;
case 'comedy' :
$result = 30000;
if ($value['audience'] > 20) {
$result += 10000 + 500 * ($value['audience'] - 20);
}
$result += 300 * $value['audience'];
break;
default:
echo("unknown type: {$this->playFor($value)['type']}");
}
return $result;
}
/**
* 放映
*
* @param $value
* @return mixed
*/
public function playFor($value)
{
return $this->plays[$value['playID']];
}
/**
* 總金額
*
* @param $statementData
* @return float|int
*/
private function totalAmount($statementData)
{
$result = 0;
foreach ($statementData['performances'] as $key => $value) {
$result += $this->amountFor($value);
}
return $result;
}
}
$playsStr = '{
"hamlet": {"name": "Hamlet", "type": "tragedy"},
"as-like": {"name": "As You Like It", "type": "comedy"},
"othello": {"name": "Othello", "type": "tragedy"}
}';
$invoicesStr =
'[
{
"customer": "BigCo",
"performances": [
{
"playID": "hamlet",
"audience": 55
},
{
"playID": "as-like",
"audience": 35
},
{
"playID": "othello",
"audience": 40
}
]
}
]';
$plays = json_decode($playsStr, true);
$invoices = json_decode($invoicesStr, true);
$show = new Show($invoices, $plays);
echo $show->statement();
echo $show->renderStatement();
使用方法:
使用拆分迴圈:分離出累加過程
使用移動語句:將累加的宣告與累加過程集中在一起
使用提煉函式:提煉出計算總數的函式
使用內聯變數:完全移除中間的變數
重構注意事項:
重構需要小步進行,每次小步進行後進行測試,知道測試透過後再進行下一小步重構;
本作品採用《CC 協議》,轉載必須註明作者和本文連結