定義
封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。
Android 中源碼使用訪問者模式
ElementVisitor
特點
優(yōu)點
(1)各角色職責分離,符合單一職責原則。
(2)具有優(yōu)秀的擴展性。
(3)使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦,使得操作集合可以獨立變化。
(4)靈活性。缺點
(1)具體元素對訪問者公布細節(jié),違反了迪米特原則。
(2)具體元素變更時導致修改成本大。
(3)違反了依賴倒置原則,為了達到“區(qū)別對待”而依賴了具體類,沒有依賴抽象。
使用場景
(1)對象結(jié)構(gòu)比較穩(wěn)定,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作。
(2)需要對一個對象結(jié)構(gòu)中的對象進行很多不同的且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。
簡單實現(xiàn)
- 員工類
/**
* 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", "產(chǎn)品經(jīng)理: " + manager.name + ",KPI:"+ manager.KPI +",產(chǎn)品數(shù)量: "+ 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 + ",代碼數(shù)量: "+ engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
Log.d("TAG", manager.name + ",產(chǎn)品數(shù)量: "+ 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("張經(jīng)理"));
mList.add(new Engineer("Android工程師:小多"));
mList.add(new Engineer("iOS工程師:小飛"));
mList.add(new Engineer("java工程師:小熊"));
mList.add(new Manager("李經(jīng)理"));
}
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());
}
}
- 輸出結(jié)果
2019-04-12 15:02:47 D/TAG: 產(chǎn)品經(jīng)理: 張經(jīng)理,KPI:7,產(chǎn)品數(shù)量: 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: 產(chǎn)品經(jīng)理: 李經(jīng)理,KPI:7,產(chǎn)品數(shù)量: 8
2019-04-12 15:02:47 D/TAG: ----------分割線----------
2019-04-12 15:02:47 D/TAG: 張經(jīng)理,產(chǎn)品數(shù)量: 5
2019-04-12 15:02:47 D/TAG: Android工程師:小多,代碼數(shù)量: 63613
2019-04-12 15:02:47 D/TAG: iOS工程師:小飛,代碼數(shù)量: 44446
2019-04-12 15:02:47 D/TAG: java工程師:小熊,代碼數(shù)量: 81327
2019-04-12 15:02:47 D/TAG: 李經(jīng)理,產(chǎn)品數(shù)量: 8