访问者模式
访问者模式(Vistor Pattern):是一种将数据结构与数据操作分离的设计模式。是指封装一些作用于某种数据结构中的各种元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作,访问者模式属于行为型模式。
访问者模式的基本思想是针对系统中拥有的某些固定类型的对象结构(元素),在其内提供一个 accept 方法用来接受访问者对象的访问。不同的访问者对同一元素的访问内容不同,使得相同的元素集合可以产生不同的元素结果。accept 方法可以接受不同的访问者对象,然后在内部将自己转发到访问者对象 visit 方法内。
访问者模式的核心思想是解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性,我们可以通过扩展不同的数据操作类型(访问者)实现对相同元素的不同操作。
示例:我们以餐厅点菜(顾客--访问者,食谱--访问者需要访问的信息)来举例说明...
package cn.liangyy.visitor;
/**
* 食谱接口
*/
public interface IRecipe {
/**
* 食谱接受访问者顾客的访问,参数就是顾客
* @param customer
*/
void accept(ICustomer customer);
}
复制代码
package cn.liangyy.visitor;
/**
* 红烧肉类
*/
public class Meat implements IRecipe {
/**
* 食谱接受访问者顾客的访问,参数就是顾客
* @param customer
*/
@Override
public void accept(ICustomer customer) {
customer.visit(this);
}
/**
* 获取价格
* @return
*/
public String getPrice(){
return "45元/份";
}
}
复制代码
package cn.liangyy.visitor;
/**
* 蔬菜类
*/
public class Cabbage implements IRecipe {
/**
* 食谱接受访问者顾客的访问,参数就是顾客
* @param customer
*/
@Override
public void accept(ICustomer customer) {
customer.visit(this);
}
/**
* 获取价格
* @return
*/
public String getPrice(){
return "16元/份";
}
}
复制代码
package cn.liangyy.visitor;
/**
* 抽象的访问者-顾客
* 访问者中的方法个数应该与和访问数据结构中的数据种类数相同
* (被访问者访问的数据结构 --> 菜)
*/
public interface ICustomer {
/**
* 访问肉类菜
* @param meat
*/
void visit(Meat meat);
/**
* 访问蔬菜类菜
* @param cabbage
*/
void visit(Cabbage cabbage);
}
复制代码
package cn.liangyy.visitor;
/**
* 具体访问者-顾客A
*/
public class CustomerA implements ICustomer {
/**
* 访问肉类菜
* @param meat
*/
@Override
public void visit(Meat meat) {
System.out.println("肉类:"+meat.getPrice());
}
/**
* 访问蔬菜类菜
* @param cabbage
*/
@Override
public void visit(Cabbage cabbage) {
System.out.println("时蔬:"+cabbage.getPrice());
}
}
复制代码
package cn.liangyy.visitor;
import java.util.ArrayList;
import java.util.List;
/**
* 菜单类
*/
public class RestaurantMenu {
//存储菜单中的菜,也就是数据结构中的元素
private List<IRecipe> recipeList = new ArrayList<>();
//初始化菜单
public RestaurantMenu(IRecipe recipe) {
recipeList.add(recipe);
}
//添加一道菜到菜单中,即添加一种数据类型到数据结构中
public void addRecipe(IRecipe recipe){
recipeList.add(recipe);
}
//展示菜单所有
public void display(ICustomer customer){
for (IRecipe recipe : recipeList){
recipe.accept(customer);
}
}
}
复制代码
package cn.liangyy.visitor;
/**
* 访问者模式-测试
*/
public class TestVistor {
public static void main(String[] args) {
//创建一道肉类菜
IRecipe recipe = new Meat();
//将肉类菜初始化到菜单中
RestaurantMenu menu = new RestaurantMenu(recipe);
//再添加一道素菜
menu.addRecipe(new Cabbage());
//顾客A开始访问菜单中的元素(菜)
menu.display(new CustomerA());
}
}
复制代码
由上述例子,我们可以看到,如果扩展访问者,非常简单,但是如果要新增一道菜,那么所有的访问者都必须修改源码了,因为每一道菜都在访问者中对应一个方法,所以访问者模式的前提是 数据结构(菜)非常稳定。
访问者模式角色(五个角色)
抽象访问者(Vistor):接口或者抽象类都可以(如示例中的 ICustomer)。这个角色主要是定义对具体元素的 visit 方法,参数就是具体元素,理论上来说方法数等于元素个数。所以如果元素不稳定经常变化的话,那么访问者是要一直修改的,并不适合使用访问者模式。
具体访问者(ConcreteVistor):实现对具体元素的访问(如示例中的 CustomerA)。
抽象元素(Element):接口或者抽象类。定义了一个接受访问者访问的方法 accept(如示例中的 IRecipe)。
具体元素(ConcreteElement):提供接受访问者访问的具体实现,通常都是采用 visitor.visit() 来实现(如示例中的 Cabbage 和 Meat)。
结构对象(ObjectStruture):用来维护元素,并提供一个方法来接受访问者访问所有的元素(如示例中的 RestaurantMenu)。
访问者模式适用场景
访问者模式优点
访问者模式缺点
评论