Problems solved by the visitor pattern
In our code writing process, we often need to add some code to some similar objects. Let’s take a computer object printing component as an example:
/** * 抽象基类 */ abstract class Unit { /** *获取名称 */ abstract public function getName(); } /** * Cpu类 */ class Cpu extends Unit { public function getName() { return 'i am cpu'; } } /** * 内存类 */ class Memory extends Unit { public function getName() { return 'i am memory'; } } /** * 键盘类 */ class Keyboard extends Unit { public function getName() { return 'i am keyboard'; } } /** * 计算机类 */ class Computer { protected $_items = []; public function add(Unit $unit) { $this->_items[] = $unit; } public function print() { // 循环打印各个组成部分 foreach ($this->_items as $item) { $item->getName(); } } }
At this time, it is above The code seems perfect, but here comes the problem. Now we not only need to print the components, but also need to save each component to the database. Not only that, we also need to print the price of each component; at this time, if in the Unit base class Adding getPrice() and save() methods can also achieve the functions we want, but there are also problems with this. You don’t know what additional operations need to be added. If you use this method to add each new operation, As time goes by, our classes will become more and more bloated.
Implementation of Visitor Pattern
The Visitor Pattern is to solve this problem. It decouples the coupling between the data structure and the operations that act on the structure, so that the set of operations can evolve relatively freely. We Let’s take a look at the improved code below:
/** * 抽象基类 */ abstract class Unit { /** * 获取名称 */ abstract public function getName(); /** * 用来接受访问者对象,回调访问者的visit方法 * 非常关键的方法 */ public function accept(Visitor $visitor) { $method = visit . get_class($this); if (method_exists($visitor, $method)) { $visitor->$method($this); } } } /** * Cpu类 */ class Cpu extends Unit { public function getName() { return 'i am cpu'; } } /** * Memory类 */ class Memory extends Unit { public function getName() { return 'i am memory'; } } /** * Keyboard类 */ class Keyboard extends Unit { public function getName() { return 'i am keyboard'; } } /** * Keyboard类 */ interface Visitor { public function visitCpu(Cpu $cpu); public function visitMemory(Memory $memory); public function visitKeyboard(Keyboard $keyboard); } /** * */ class PrintVisitor implements Visitor { public function visitCpu(Cpu $cpu) { echo "hello, " . $cpu->getName() . "\n"; } public function visitMemory(Memory $memory) { echo "hello, " . $memory->getName() . "\n"; } public function visitKeyboard(Keyboard $keyboard) { echo "hello, " . $keyboard->getName() . "\n"; } } /** * */ class Computer { protected $_items = []; public function add(Unit $unit) { $this->_items[] = $unit; } /** * 调用各个组件的accept方法 */ public function accept(Visitor $visitor) { foreach ($this->_items as $item) { $item->accept($visitor); } } } $computer = new Computer(); $computer->add(new Cpu()); $computer->add(new Memory()); $computer->add(new Keyboard()); $printVisitor = new PrintVisitor(); $computer->print($printVisitor); // 以上的代码将打印出 hello, i am cpu hello, i am memory hello, i am keyboard
Summary
After the above improvements, it becomes very easy for us to expand. If we need to add a new method of saving to the database, we can add a new one that implements Visitor Class, such as SaveVisitor, implementing the save method in this class is equivalent to decoupling the class and some operations in the class, and the object that collects the class operations is the visitor.
The above is the entire content of this article. I hope it will be helpful to everyone’s learning. I also hope that everyone will support the PHP Chinese website.
For more articles related to easily mastering the visitor pattern of PHP design patterns, please pay attention to the PHP Chinese website!