《PHP設計模式介紹》第十二章 裝飾器模式(4)_PHP教程
推薦:《PHP設計模式介紹》第十一章 代理模式因為某個對象消耗太多資源,而且你的代碼并不是每個邏輯路徑都需要此對象, 你曾有過延遲創(chuàng)建對象的想法嗎 ( if和else就是不同的兩條邏輯路徑) ? 你有想過限制訪問某個對象,也就是說,提供一組方法
現(xiàn)在。我們繼續(xù)為表單添加一些驗證機制。方法是編輯另一個組件裝飾器類來表達一個“invalid”狀態(tài)并擴展FormHandler類增加一個validate方法以處理組件示例數(shù)組。如果組件非法(“invalid”),我們通過一個“invalid”類將它包裝在<span>元素中。這里是一個證明這個目標的測試
class WidgetTestCase extends UnitTestCase { // ... function testInvalid() { $text =& new Invalid(new TextInput(‘email’)); $output = $text->paint(); $this->assertWantedPattern( ‘~^<span class=”invalid”><input[^>] ></span>$~i’, $output); } } |
這里是Invalid WidgetDecorator子類:
//代碼Here’s the Invalid WidgetDecorator subclass:
class Invalid extends WidgetDecorator { function paint() { eturn ‘<span class=”invalid”>’.$this->widget->paint().’</span>’; } } |
裝飾器的一個有點是你可以將他們串在一起(使用)。Invalid裝飾器僅僅知道:它正在包裝一個組件:它不必關心組件是否是一個TextInput, Select,或者是一個有標簽的被裝飾版本的組件 。
這導致了下一個合理的測試用例:
class WidgetTestCase extends UnitTestCase { // ... function testInvalidLabeled() { $text =& new Invalid( new Labeled( ‘Email’ ,new TextInput(‘email’))); $output = $text->paint(); $this->assertWantedPattern(‘~<b>Email:</b> <input~i’, $output); $this->assertWantedPattern( ‘~^<span class=”invalid”>.*</span>$~i’, $output); } } |
有了Invalid裝飾器,我們來處理FormHandler::validate() 方法:
class FormHandlerTestCase extends UnitTestCase { // ... function testValidateMissingName() { $post =& new Post; $post->set(‘fname’, ‘Jason’); $post->set(‘email’, ‘jsweat_php@yahoo.com’); $form = FormHandler::build($post); $this->assertFalse(FormHandler::validate($form, $post)); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[0]->paint()); $this->assertWantedPattern(‘/invalid/i’, $form[1]->paint()); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[2]->paint()); } } |
這個測試捕獲(包含)了所有的基本方面:建立一個Post實例的存根,使用它建立一個組件集合,然后將集合傳送給validate方法。
class FormHandler { function validate(&$form, &$post) { // first name required if (!strlen($post->get(‘fname’))) { $form[0] =& new Invalid($form[0]);} // last name required if (!strlen($post->get(‘lname’))) { $form[1] =& new Invalid($form[1]); } } } |
不協(xié)調(diào)的代碼
當我看這段代碼時,我發(fā)現(xiàn)了兩個不協(xié)調(diào)之處:通過數(shù)字索引訪問表單元素,需要傳遞$_post數(shù)組。給validation方法。在以后的重構中,最好是創(chuàng)建一個組件集合用一個以表單元素名字索引的關聯(lián)數(shù)組表示或者用一個Registry模式作為更合理的一步。你也可以給類Widget增加一個方法返回它的
當前數(shù)值,取消需要傳遞$_Post實例給Widget集合的構造函數(shù)。所有這些都超出了這個例子目的的范圍。
為了驗證目的,我們繼續(xù)增加一個簡單的 正則方法(regex)來驗證email地址:
class FormHandlerTestCase extends UnitTestCase { // ... function testValidateBadEmail() { $post =& new Post; $post->set(‘fname’, ‘Jason’); $post->set(‘lname’, ‘Sweat’); $post->set(‘email’, ‘jsweat_php AT yahoo DOT com’); $form = FormHandler::build($post); $this->assertFalse(FormHandler::validate($form, $post)); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[0]->paint()); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[1]->paint()); $this->assertWantedPattern(‘/invalid/i’, $form[2]->paint()); } } |
實現(xiàn)這個簡單的email驗證的代碼如下:
//代碼
class FormHandler { function validate(&$form, &$post) { // first name required if (!strlen($post->get(‘fname’))) { $form[0] =& new Invalid($form[0]);} // last name required if (!strlen($post->get(‘lname’))) { $form[1] =& new Invalid($form[1]); } // email has to look real if (!preg_match(‘~\w @(\w \.) \w ~’ ,$post->get(‘email’))) { $form[2] =& new Invalid($form[2]); } } } |
你也可以創(chuàng)建一個測試用例以驗證form表單何時有效://代碼
class FormHandlerTestCase extends UnitTestCase { // ... function testValidate() { $post =& new Post; $post->set(‘fname’, ‘Jason’); $post->set(‘lname’, ‘Sweat’); $post->set(‘email’, ‘jsweat_php@yahoo.com’); $form = FormHandler::build($post); $this->assertTrue(FormHandler::validate($form, $post)); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[0]->paint()); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[1]->paint()); $this->assertNoUnwantedPattern(‘/invalid/i’, $form[2]->paint()); } } |
這又提出了在本方法內(nèi)追蹤任何驗證失敗的需求,因此它可以返回true如果所有的都合格。
分享:《PHP設計模式介紹》第十章 規(guī)范模式在一個應用軟件的成型過程中,一些意想不到的商業(yè)邏輯到處出現(xiàn)。比如,基于價格的考慮,這個任務必須減少項目;而那個任務也因為銷售稅而必須選擇合適的比率;而其它的任務也必須因為其他的特別
- 相關鏈接:
- 教程說明:
PHP教程-《PHP設計模式介紹》第十二章 裝飾器模式(4)。