《PHP设计模式介绍》第十二章 装饰器模式(4)_PHP教程
推荐:《PHP设计模式介绍》第十一章 代理模式因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法
现在。我们继续为表单添加一些验证机制。方法是编辑另一个组件装饰器类来表达一个“invalid”状态并扩展FormHandler类增加一个validate方法以处理组件示例数组。如果组件非法(“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]); } } } |
不协调的代码
当我看这段代码时,我发现了两个不协调之处:通过数字索引访问表单元素,需要传递$_post数组。给validation方法。在以后的重构中,最好是创建一个组件集合用一个以表单元素名字索引的关联数组表示或者用一个Registry模式作为更合理的一步。你也可以给类Widget增加一个方法返回它的
当前数值,取消需要传递$_Post实例给Widget集合的构造函数。所有这些都超出了这个例子目的的范围。
为了验证目的,我们继续增加一个简单的 正则方法(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()); } } |
实现这个简单的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]); } } } |
你也可以创建一个测试用例以验证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()); } } |
这又提出了在本方法内追踪任何验证失败的需求,因此它可以返回true如果所有的都合格。
分享:《PHP设计模式介绍》第十章 规范模式在一个应用软件的成型过程中,一些意想不到的商业逻辑到处出现。比如,基于价格的考虑,这个任务必须减少项目;而那个任务也因为销售税而必须选择合适的比率;而其它的任务也必须因为其他的特别
- 相关链接:
- 教程说明:
PHP教程-《PHP设计模式介绍》第十二章 装饰器模式(4)。