文章目录
模式概述
设想一下,在开发中,甲方总是会变更他的需求,在不采用访问者模式的情况下,我们就需要反复地修改对象的结构。举个例子:今天一个投资人找到我,说“小奇啊,我看我家楼下开了个特别好吃的煎饼果子店,每天早上生意都爆火,我也想开一家”。 我想,这有啥难的,开呗!但是店都装修好了,准备开张的时候,投资人又找到我说:“小奇啊,我家楼下的煎饼果子店倒闭了,开了家新店,卖新疆炒米粉的,我不想开煎饼果子店了,我要开新疆炒米粉店!”。我心想,行吧,您有钱您说的算。我把店铺重新装修了下,准备重新开张,但是在前一天晚上投资人又找到我说:“小奇啊,我觉着新疆炒米粉太辣了,我还是喜欢吃煎饼果子,咱们还是开煎饼果子店吧。”;我心想:大哥!你到底要怎样啊,要是你明天又想吃新疆炒米粉咋办!这样来来回回也不行,有没有办法解决呢? 我说:“这样吧哥,我开个小吃摊,左边是煎饼果子右边是新疆炒米粉,您要是以后又喜欢吃别的了,咱们再加一个摊位,这样您想吃啥去点啥就行了,可以不?”,大哥一听:“好主意啊!”。
这就是访问者模式:在不改变现有对象结构情况下,添加新的功能。
访问者模式结构
在访问者模式结构图中包含如下几个角色:
Visitor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。
ConcreteVisitor(具体访问者):具体访问者(比如boss和customer)实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。
Element(抽象元素):抽象元素一般是抽象类或者接口(比如这里的stand小摊),它定义了一个 accept()方法 ,该方法通常以一个抽象访问者作为参数。
ConcreteElement(具体元素):具体元素(比如这里的product产品) 实现了accept()方法 ,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。
模式代码
Visitor(抽象访问者)
public interface Visitor {
//访问产品信息
void visit(Product product);
}
ConcreteVisitor(具体访问者)
public class Boss implements Visitor {
@Override
public void visit(Product product) {
System.out.println("产品销量:" + product.amount() + ";产品利润:" + product.profit());
}
}
public class Customer implements Visitor {
@Override
public void visit(Product product) {
System.out.println("产品名字:" + product.name+"; 单价:" + product.price);
}
}
Element(抽象元素)
public abstract class Stand {
public String name; //店铺名字
public int price; //单价
public Stand(String name, int price) {
this.name = name;
this.price = price;
}
// 核心访问方法
public abstract void accept(Visitor visitor);
}
ConcreteElement(具体元素)
public class Product extends Stand {
public Product(String name, int price) {
super(name, price);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int amount(){
return (int)(Math.random() * 100);
}
public int profit(){
return amount() * price;
}
}
目的
我们希望:
- customer(顾客)访问的时候,看到的是产品的名字和单价
- boss(老板)访问的时候,看到的是产品的销售量和利润
- 可以根据需求增加或减少摊位,且不改变摊位这个对象的结构(也就是摊位还是由产品的名字和单价组成)