访问者模式
访问者模式
1.访问者模式的本质
访问者模式的本质:预留通路,回调实现。
访问者模式的本质是将数据结构和数据操作分离,通过定义一个访问者对象,实现对数据结构中各个元素的访问和处理,从而达到解耦和灵活性的目的。
2.何时选用访问者模式
建议在以下情况中选用访问者模式。
-
当需要对一个复杂的数据结构进行操作,并且这些操作可能需要根据不同的元素类型进行变化时,可以考虑使用访问者模式。通过将具体操作封装在访问者对象中,可以在不改变数据结构的情况下,实现对不同元素的不同操作。
-
当需要在不同的数据结构中执行相似的操作,但不希望在数据结构中添加新的方法时,可以使用访问者模式。访问者模式可以将操作从数据结构中分离出来,使得操作可以独立变化,而不需要修改数据结构本身。
-
当数据结构中的元素种类相对稳定,但可能需要新增一些新的操作时,可以考虑使用访问者模式。通过定义新的访问者对象,可以在不修改现有元素类的情况下,对新增操作进行扩展。
-
当需要对数据结构中的元素进行多种操作,并且这些操作之间存在一定的关联或依赖关系时,可以使用访问者模式。访问者模式可以通过在访问者中保存中间结果或状态,实现多个操作之间的数据共享和协作。
3.优缺点
访问者模式有以下优点。
-
好的扩展性
能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。 -
好的复用性
可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。 -
分离无关行为
可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。
访问者模式有以下缺点。
-
对象结构变化很困难
不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。 -
破坏封装
访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。
4.访问者模式的结构
- Visitor:访问者接口,为所有的访问者对象声明一个visit方法,用来代表为对象结构添加的功能,理论上可以代表任意的功能。
- ConcreteVisitor:具体的访问者实现对象,实现要真正被添加到对象结构中的功能。Element:抽象的元素对象,对象结构的顶层接口,定义接受访问的操作。
- ConcreteElement:具体元素对象,对象结构中具体的对象,也是被访问的对象,通常会回调访问者的真实功能,同时开放自身的数据供访问者使用。
- ObjectStructure:对象结构,通常包含多个被访问的对象,它可以遍历多个被访问的对象,也可以让访问者访问它的元素。可以是一个复合或是一个集合,如一个列表或无序集合。
5.实现
模拟大众公司生产油车和电车
- 销售人员关注油车和电车的价格
- 质检人员关注油车和电车的油耗量和电耗量
1.大众汽车接口及其实现类
/**
* @description:大众汽车
*/
public interface Car {
/**
* 接受访问者的访问
* @param visitor 访问者对象
*/
void accept(Visitor visitor);
}
/**
* @description:大众辉腾(油车)
*/
@Data
@AllArgsConstructor
public class HuiTeng implements Car{
/**
* 价格
*/
private String price;
/**
* 油耗量
*/
private String oilConsumption;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* @description:大众朗逸(电车)
*/
@Data
@AllArgsConstructor
public class LangYi implements Car {
/**
* 价格
*/
private String price;
/**
* 耗电量
*/
private String powerConsumption;
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
2.访问者接口及其实现类
/**
* @description:访问者接口
*/
public interface Visitor {
/**
* 给辉腾增加访问者功能
* @param huiTeng
*/
void visit(HuiTeng huiTeng);
/**
* 给朗逸增加访问者功能
* @param langYi
*/
void visit(LangYi langYi);
}
/**
* @description:销售访问者
*/
public class Sales implements Visitor{
@Override
public void visit(HuiTeng huiTeng) {
System.out.println("销售人员只关注辉腾的价格,价格为:"+huiTeng.getPrice());
}
@Override
public void visit(LangYi langYi) {
System.out.println("销售人员只关注朗逸的价格,价格为:"+langYi.getPrice());
}
}
/**
* @description:质检访问者
*/
public class Quality implements Visitor{
@Override
public void visit(HuiTeng huiTeng) {
System.out.println("质检人员只关注辉腾的油耗量,油耗量为:"+huiTeng.getOilConsumption());
}
@Override
public void visit(LangYi langYi) {
System.out.println("质检人员只关注朗逸的电耗量,电耗量为:"+langYi.getPowerConsumption());
}
}
3.大众汽车结构类
/**
* @description:汽车结构对象
*/
public class CarStructure {
/**
* 要操作的汽车集合
*/
private List<Car> list = new ArrayList<>();
/**
* 添加汽车
*
* @param car
*/
public void addCar(Car car) {
list.add(car);
}
public void handle(Visitor visitor) {
//遍历,接受访问
for (Car car : list) {
car.accept(visitor);
}
}
}
4.测试类
public class Client {
public static void main(String[] args) {
HuiTeng huiTeng = new HuiTeng("100w", "14.5L/100km");
LangYi langYi = new LangYi("20w", "13.2kWh/100km");
CarStructure carStructure = new CarStructure();
carStructure.addCar(huiTeng);
carStructure.addCar(langYi);
//访问
carStructure.handle(new Sales());
carStructure.handle(new Quality());
}
}
5.结果