访问者模式是一种比较复杂且不常用的例子。访问者模式是为了解决稳定的数据结构和易变的操作耦合问题。
一个类的结构很少改变,但经常需要在此类中定义新的操作。 在需要对这个类定义很多不同的并且不相关的操作,而且要避免让这些操作"污染"这个类,也不希望在增加新操作时修改这个类,就需要使用visitor pattern。
提到访问者,一下就想起了看望病人的例子,这里就以探望病人为例写个demo,虽然简单,但也能体现访问者模式的使用及特点。
package visitor;
public abstract class Patient {
String name;
String disease;
public Patient(String name, String disease) {
super();
this.name = name;
this.disease = disease;
}
public abstract void accept(Visitor visitor);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisease() {
return disease;
}
public void setDisease(String disease) {
this.disease = disease;
}
}
package visitor;
public class APatient extends Patient{
public APatient(String name, String disease) {
super(name, disease);
}
@Override
public void accept(Visitor visitor) {
visitor.visitAPatient(this);
}
public void visitedByAVisitor() {
System.out.println("滚");
}
public void visitedByBVisitor() {
System.out.println("没事");
}
}
package visitor;
public class BPatient extends Patient{
public BPatient(String name, String disease) {
super(name, disease);
}
@Override
public void accept(Visitor visitor) {
visitor.visitBPatient(this);
}
public void beatAVisitor() {
System.out.println("打死你");
}
public void thankBVisitor() {
System.out.println("谢谢");
}
}
package visitor;
public interface Visitor {
void visitAPatient(APatient aPatient);
void visitBPatient(BPatient bPatient);
}
package visitor;
public class AVisitor implements Visitor{
@Override
public void visitAPatient(APatient aPatient) {
System.out.println(String.format("%s,你说你嘴上起个泡,其实你得的是%s",
aPatient.getName(),aPatient.getDisease()));
aPatient.visitedByAVisitor();
}
@Override
public void visitBPatient(BPatient bPatient) {
System.out.println(String.format("%s,你说你嘴上起个泡,其实你得的是%s",
bPatient.getName(),bPatient.getDisease()));
bPatient.beatAVisitor();
}
}
package visitor;
public class BVisitor implements Visitor{
@Override
public void visitAPatient(APatient aPatient) {
System.out.println(String.format("%s,你身体怎么样,%s不严重吧",
aPatient.getName(),aPatient.getDisease()));
aPatient.visitedByBVisitor();
}
@Override
public void visitBPatient(BPatient bPatient) {
System.out.println(String.format("%s,你身体怎么样,%s不严重吧",
bPatient.getName(),bPatient.getDisease()));
bPatient.thankBVisitor();
}
}
package visitor;
import java.util.ArrayList;
import java.util.List;
public class HospitalObjectStructure {
List<Patient> patients=new ArrayList<>();
public void addPatients(Patient patient) {
patients.add(patient);
}
public void visitArrangement(Visitor visitor) {
patients.stream().forEach(item->item.accept(visitor));
}
}
package visitor;
public class Client {
public static void main(String[] args) {
APatient aPatient=new APatient("张三","痔疮");
BPatient bPatient=new BPatient("李四","拉肚子");
HospitalObjectStructure hospital=new HospitalObjectStructure();
hospital.addPatients(aPatient);
hospital.addPatients(bPatient);
Visitor aVisitor=new AVisitor();
Visitor bVisitor=new BVisitor();
hospital.visitArrangement(aVisitor);
hospital.visitArrangement(bVisitor);
}
}
打印结果:
张三,你说你嘴上起个泡,其实你得的是痔疮
滚
李四,你说你嘴上起个泡,其实你得的是拉肚子
打死你
张三,你身体怎么样,痔疮不严重吧
没事
李四,你身体怎么样,拉肚子不严重吧
谢谢
小结:
1.什么使用访问者模式:对象结构足够稳定,需要经常定义新的操作;
2.访问者模式的缺点:
(1)Patient对Visitor公布细节,违反了迪米特原则;
(2)Patient变更时导致修改成本大,变更Patient属性时,多个Visotor的实现类都要修改;
(3)违反了依赖倒置原则,为了达到“区别对待”而依赖了具体类,没有依赖接口,Visitor接口中,依赖的是Patient的实现类。