模式定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下,定义作用于这些元素的新操作
使用场景
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
例子
定义被访问者学生。抽象了一个学生基类,随机数来模拟总成绩
public abstract class Students {
public String name;
public int totalScore; // 总成绩
Students(String aName) {
name = aName;
totalScore = new Random().nextInt(100);
}
public abstract void accept(Visitor visitor);
}
然后我们定义了两种学生
// 体育生,随机数模拟成绩
public class SportsStudents extends Students {
public int sports;
public SportsStudents(String aName) {
super(aName);
sports = new Random().nextInt(100);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 美术生,随机数模拟成绩
public class ArtStudents extends Students {
public int art;
public ArtStudents(String aName) {
super(aName);
art = new Random().nextInt(100);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
先抽象出访问者的访问方法visit
public interface Visitor {
public void visit(ArtStudents artStudents);
public void visit(SportsStudents sportsStudents);
}
这里定义两个访问者,一个班主任,他关注总成绩和特长科目成绩。另一个特长老师,他只关心特长科目成绩
// 班主任
public class HeadmasterTeacherVisitor implements Visitor {
private static String TAG = ArtStudents.class.getSimpleName();
@Override
public void visit(ArtStudents artStudents) {
Log.d(TAG,"name = " + artStudents.name);
Log.d(TAG,"totalScore = " + artStudents.totalScore);
Log.d(TAG,"art = " + artStudents.art);
}
@Override
public void visit(SportsStudents sportsStudents) {
Log.d(TAG,"name = " + sportsStudents.name);
Log.d(TAG,"totalScore = " + sportsStudents.totalScore);
Log.d(TAG,"sports = " + sportsStudents.sports);
}
}
// 特长老师
public class SpecialTeacherVisitor implements Visitor {
private static String TAG = SpecialTeacherVisitor.class.getSimpleName();
@Override
public void visit(ArtStudents artStudents) {
Log.d(TAG,"name = " + artStudents.name);
Log.d(TAG,"art = " + artStudents.art);
}
@Override
public void visit(SportsStudents sportsStudents) {
Log.d(TAG,"name = " + sportsStudents.name);
Log.d(TAG,"sports = " + sportsStudents.sports);
}
}
根据不同的访问者和被访问者达到不同的操作目的,这里模拟把所有学生放到一个list里面。遍历的时候,被访问者students调用accept访问来同意访问
public class StudentsList {
List<Students> list = new LinkedList<Students>();
public StudentsList() {
list.add(new ArtStudents("jack"));
list.add(new ArtStudents("john"));
list.add(new SportsStudents("lily"));
list.add(new SportsStudents("sky"));
}
public void showStudentschievement(Visitor visitor) {
for (Students students : list) {
students.accept(visitor);
}
}
}
调用:
StudentsList list = new StudentsList();
list.showStudentschievement(new HeadmasterTeacherVisitor());
list.showStudentschievement(new SpecialTeacherVisitor());
输出:
D/ArtStudents: name = jack
D/ArtStudents: totalScore = 13
D/ArtStudents: art = 52
D/ArtStudents: name = john
D/ArtStudents: totalScore = 98
D/ArtStudents: art = 12
D/ArtStudents: name = lily
D/ArtStudents: totalScore = 51
D/ArtStudents: sports = 23
D/ArtStudents: name = sky
D/ArtStudents: totalScore = 24
D/ArtStudents: sports = 30
D/SpecialTeacherVisitor: name = jack
D/SpecialTeacherVisitor: art = 52
D/SpecialTeacherVisitor: name = john
D/SpecialTeacherVisitor: art = 12
D/SpecialTeacherVisitor: name = lily
D/SpecialTeacherVisitor: sports = 23
D/SpecialTeacherVisitor: name = sky
D/SpecialTeacherVisitor: sports = 30
总结
优点:
- 符合单一职责原则
- 优秀的扩展性以及灵活性
缺点:
- 具体元素对访问者公布细节,违反了迪米特原则
- 具体元素变更比较困难
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象