定义
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
Android 中源码使用访问者模式
ElementVisitor
特点
优点
(1)各角色职责分离,符合单一职责原则。
(2)具有优秀的扩展性。
(3)使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
(4)灵活性。缺点
(1)具体元素对访问者公布细节,违反了迪米特原则。
(2)具体元素变更时导致修改成本大。
(3)违反了依赖倒置原则,为了达到“区别对待”而依赖了具体类,没有依赖抽象。
使用场景
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
简单实现
- 员工类
/**
* Created on 2019/4/12 14:33
*
* @author Scarf
*/
public abstract class Staff {
public String name;
public int KPI;
public Staff(String name) {
this.name = name;
this.KPI = new Random().nextInt(10);
}
public abstract void accept(Visitor visitor);
}
------------------------------------
/**
* Created on 2019/4/12 14:37
*
* @author Scarf
*/
public class Engineer extends Staff {
private int codeLines;
public Engineer(String name) {
super(name);
codeLines = new Random().nextInt(10 * 10000);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getCodeLines() {
return codeLines;
}
}
------------------------------------
/**
* Created on 2019/4/12 14:39
*
* @author Scarf
*/
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.visit(this);
}
public int getProducts() {
return products;
}
}
- 访问接口
/**
* Created on 2019/4/12 14:35
*
* @author Scarf
*/
public interface Visitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
--------------------------------
/**
* Created on 2019/4/12 14:42
*
* @author Scarf
*/
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
Log.d("TAG", engineer.name + ",KPI: "+ engineer.KPI );
}
@Override
public void visit(Manager manager) {
Log.d("TAG", "产品经理: " + manager.name + ",KPI:"+ manager.KPI +",产品数量: "+ manager.getProducts());
}
}
--------------------------------
/**
* Created on 2019/4/12 14:42
*
* @author Scarf
*/
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
Log.d("TAG", engineer.name + ",代码数量: "+ engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
Log.d("TAG", manager.name + ",产品数量: "+ manager.getProducts());
}
}
- 报表类
/**
* Created on 2019/4/12 14:45
*
* @author Scarf Gong
*/
public class Report {
private List<Staff> mList = new ArrayList<>();
public Report() {
mList.add(new Manager("张经理"));
mList.add(new Engineer("Android工程师:小多"));
mList.add(new Engineer("iOS工程师:小飞"));
mList.add(new Engineer("java工程师:小熊"));
mList.add(new Manager("李经理"));
}
public void showReport(Visitor visitor) {
for (Staff staff : mList) {
staff.accept(visitor);
}
}
}
- 使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
Report report = new Report();
report.showReport(new CEOVisitor());
Log.d("TAG", "----------分割线----------");
report.showReport(new CTOVisitor());
}
}
- 输出结果
2019-04-12 15:02:47 D/TAG: 产品经理: 张经理,KPI:7,产品数量: 5
2019-04-12 15:02:47 D/TAG: Android工程师:小多,KPI: 5
2019-04-12 15:02:47 D/TAG: iOS工程师:小飞,KPI: 3
2019-04-12 15:02:47 D/TAG: java工程师:小熊,KPI: 1
2019-04-12 15:02:47 D/TAG: 产品经理: 李经理,KPI:7,产品数量: 8
2019-04-12 15:02:47 D/TAG: ----------分割线----------
2019-04-12 15:02:47 D/TAG: 张经理,产品数量: 5
2019-04-12 15:02:47 D/TAG: Android工程师:小多,代码数量: 63613
2019-04-12 15:02:47 D/TAG: iOS工程师:小飞,代码数量: 44446
2019-04-12 15:02:47 D/TAG: java工程师:小熊,代码数量: 81327
2019-04-12 15:02:47 D/TAG: 李经理,产品数量: 8