访问者模式
定义: 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作.
使用场景:
- 对象结构比较稳定,但经常需要再此对象结构上定义新的操作.
- 需要对一个对象结构中的对象进行很多不同的而且不相关的操作,而需要避免这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类.
优点:
- 各角色职责分离,符合单一职责原则;
- 具有优秀的扩展性;
- 使得数据结构和作用于结构上操作解耦,使得操作集合可以独立变化;
- 灵活性;
缺点:
- 具体元素对访问者公布细节,违反了迪米特原则;
- 具体元素变更时导致修改成本大;
- 违反了依赖倒置原则,为了达到"区别对待"而依赖了具体类,没有依赖抽象;
举个例子:
//员工基类
public abstract class Staff {
public String name;
//员工kpi
public int kpi;
public Staff(String name) {
this.name = name;
}
//接受Visitor的访问
public abstract void accept(Visitor visitor);
}
public class Manager extends Staff{
private int products; //产品数量
public Manager(String name) {
super(name);
products = new Random().nextInt(10);
}
@Override
public void accept(Visitor visitor) {
visitor.visitor(this);
}
//一年内做的产品数量
public int getProducts(){
return products;
}
}
public class Engineer extends Staff{
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visitor(this);
}
//码农一年写了代码行数
public int getCodeLine(){
return new Random().nextInt(10*1000);
}
}
public interface Visitor {
public void visitor(Engineer engineer);
public void visitor(Manager manager);
}
public class CEOVisitor implements Visitor{
@Override
public void visitor(Engineer engineer) {
System.out.println("码农:"+engineer.name+ " , KPI : "+engineer.kpi);
}
@Override
public void visitor(Manager manager) {
System.out.println("经理 : "+ manager.name +" , KPI : "+manager.kpi+" , 新产品数量 : "+ manager.getProducts());
}
}
public class CTOVisitor implements Visitor{
@Override
public void visitor(Engineer engineer) {
System.out.println("码农 : " + engineer.name +" , 代码行数 :"+ engineer.getCodeLine());
}
@Override
public void visitor(Manager manager) {
System.out.println("经理 : "+manager.name +" , 产品数量 : "+ manager.getProducts());
}
}
//员工报表1
public class BusinessReport {
List<Staff> staff = new LinkedList<Staff>();
public BusinessReport() {
staff.add(new Manager("王经理"));
staff.add(new Engineer("码农-小张"));
staff.add(new Engineer("码农-小李"));
staff.add(new Engineer("码农-小陈"));
staff.add(new Engineer("码农-小钱"));
}
//为访问者展示报表,
public void showReport(Visitor visitor){
for (Staff staff:staff){
staff.accept(visitor);
}
}
}
public static void main(String[] args) {
BusinessReport report = new BusinessReport();
System.out.println("===============CEO===========");
report.showReport(new CEOVisitor());
System.out.println("===============CTO===========");
report.showReport(new CTOVisitor());
}