概要
処理毎にメソッドを分けて、分けたメソッドの中で情報を蓄積していくパターン。
これに名前があったのかと驚いて、コレジャナイと思い 調べ直しをしすぎて調べるのにすごく時間がかかった。
利点
1つの変数に加工した値をまとめて返す場合のリファクタリングがしやすくなったり、可読性が向上する。
例
HTMLファイルが参照している外部ファイルを、HTMLを埋め込んだ形に変更する。
PHPで書いてみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class HtmlConverter { public function toMonolithic(string $html) : string { $doc = new DOMDocument(); libxml_use_internal_errors(true); $doc->loadHTML($html); libxml_clear_errors();
$linkNode = $doc->getElementsByTagName('link');
for ($i = 0, $count = $linkNode->length - 1; $i <= $count; $i++) { $child = $linkNode->item(0); $path = $child->getAttribute('href'); $css_string = file_get_contents($path); $replace_elm = $doc->createElement('style', $css_string); $elm_type_attr = $doc->createAttribute('type'); $elm_type_attr->value = 'text/css'; $replace_elm->appendChild($elm_type_attr); $child->parentNode->replaceChild($replace_elm, $child); }
$scriptNode = $doc->getElementsByTagName('script');
$skip_item_count = 0; for ($i = 0, $count = $scriptNode->length - 1; $i <= $count; $i++) { $child = $scriptNode->item($skip_item_count); if (empty($child) && ! $child->hasAttribute('src')) { $skip_item_count++; continue; } $path = $child->getAttribute('src'); $javascript_string = file_get_contents($path); $replace_elm = $doc->createElement('script'); $replace_elm->appendChild($doc->createTextNode($javascript_string)); $child->parentNode->replaceChild($replace_elm, $child); }
$imgNode = $doc->getElementsByTagName('img'); foreach ($imgNode as $child) { $path = $child->getAttribute('src'); $ext = substr($path, (strrpos($path, '.') + 1 )); $img_binary = base64_encode(file_get_contents($path)); $child->setAttribute('src', 'data:image/'.$ext.';base64,'.$img_binary); }
return $doc->saveHTML(); } }
|
この様に1メソッドが長い。
この中で、情報を蓄積しているDOMDocument
オブジェクト($doc変数)が存在する
以下の様に処理毎にメソッドを分割する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| class HtmlConverter { public function toMonolithic(string $html) : string { $doc = new DOMDocument(); libxml_use_internal_errors(true); $doc->loadHTML($html); libxml_clear_errors();
$this->replaceLinkTag($doc); $this->replaceScriptTag($doc); $this->replaceImgTag($doc);
return $doc->saveHTML(); }
private function replaceLinkTag(DOMDocument $doc) : void { $linkNode = $doc->getElementsByTagName('link');
for ($i = 0, $count = $linkNode->length - 1; $i <= $count; $i++) { $child = $linkNode->item(0); $path = $child->getAttribute('href'); $css_string = file_get_contents($path); $replace_elm = $doc->createElement('style', file_get_contents($path)); $elm_type_attr = $doc->createAttribute('type'); $elm_type_attr->value = 'text/css';
$replace_elm->appendChild($elm_type_attr); $child->parentNode->replaceChild($replace_elm, $child); } }
private function replaceScriptTag(DOMDocument $do) : void { $scriptNode = $doc->getElementsByTagName('script');
$skip_item_count = 0; for ($i = 0, $count = $scriptNode->length - 1; $i <= $count; $i++) { $child = $scriptNode->item($skip_item_count); if (empty($child) && ! $child->hasAttribute('src')) { $skip_item_count++; continue; }
$path = $child->getAttribute('src'); $javascript_string = file_get_contents($path); $replace_elm = $doc->createElement('script');
$replace_elm->appendChild($doc->createTextNode($javascript_string)); $child->parentNode->replaceChild($replace_elm, $child); } }
private function replaceImgTag(DOMDocument $doc) : void { $imgNode = $doc->getElementsByTagName('img');
foreach ($imgNode as $child) { $path = $child->getAttribute('src'); $ext = substr($path, (strrpos($path, '.') + 1 )); $img_binary = base64_encode(file_get_contents($path)); $child->setAttribute('src', 'data:image/'.$ext.';base64,'.$img_binary); } } }
|
なんということでしょう。
長かった1メソッドが、処理毎に分割され、リファクタリングを行いやすい様に生まれ変わりました。
また、これらの分割されたメソッドの引数として、
情報を蓄積しているDOMDocument
オブジェクトを渡してそれぞれのメソッド内で情報を更新させるということを繰り返す。
まとめ
- 情報を蓄積するオブジェクトを 作る or 見つける。
- 処理毎にメソッドを抽出し、情報を累積するオジェクトをパラメータとして渡す。
- これらを繰り返す。
参考
Move Accumulation to Collecting Parameter - Refactoring - Measure and Improve Code Quality continuously with Scrutinizer
書籍 Refactoring to Patterns | Accumulation| Move Accumulation to Collecting Parameter
Move Accumulation to Collecting Parameter