B7:访问者模式 Visitor
表示一个作用于某对象结构中各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作.
适用场景:
1.适用于元素类数据结构相对稳定(类的方法固定,但属性可以变化,如果方法变化很大,就无法使用访问者)
2.把数据的处理从数据结构上分离出来.
3.需要一个结构对象角色,组合一系列的元素类.
与装饰器模式的区别
1.装饰器模式通常是单个对象的装饰,为这个对象动态扩展了方法,也就是扩展了对象的结构,所以归为结构模式;访问者模式通常用于收集一组元素类的信息,所以归为行为模式.
2.装饰器模式不需要被装饰者有稳定的结构,被装饰者不需要知道装饰者,其中也无需增加装饰者.访问模式,需要元素类有稳定的结构,留有一个接口,来增加访问者.
UML
示例:
// 产品接口(元素类接口) interface ProductInterface { public function addVisitor(VisitorInterface $visitor); } // 访问者接口 interface VisitorInterface { public function visit(ProductInterface $product); } // 具体产品类1 class Product1 implements ProductInterface { public function addVisitor(VisitorInterface $visitor) { $visitor->visit($this); } public function getTotalExpend() { echo '总计支出1000'; } public function getTotalEarn() { echo '总计收入10000'; } } // 具体产品类2 class Product2 implements ProductInterface { public function addVisitor(VisitorInterface $visitor) { $visitor->visit($this); } public function getTotalExpend() { echo '总计支出500'; } public function getTotalEarn() { echo '总计收入5000'; } } // 销售主管,需要统计总收入 class Visitor1 implements VisitorInterface { public function visit(ProductInterface $product) { $product->getTotalEarn(); } } // 产品统筹需要统计总支出 class Visitor2 implements VisitorInterface { public function visit(ProductInterface $product) { $product->getTotalExpend(); } } // 结构对象角色,这对于访问者来说是必备的,访问者模式处理了一组元素类,而不是单个的元素类 class ObjectStruct { protected $products = []; public function attach(ProductInterface $product) { $this->products[] = $product; } public function getProductList() { return $this->products; } } // 客户调用 $obj = new ObjectStruct(); $obj->attach(new Product1()); $obj->attach(new Product2()); $lists = $obj->getProductList(); // 销售主管访问者 $visitor1 = new Visitor1(); foreach ($lists as $product) { $product->addVisitor($visitor1); } // 产品统筹 $visitor2 = new Visitor2(); foreach ($lists as $product2) { $product2->addVisitor($visitor2); }