**定義**:封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用于這些元素的新的操作。
## 一般模式

Visitor----抽象訪問者
--|抽象類或接口,聲明訪問者可以訪問那些元素,具體到程序中的就是visit的參數定義那些對象是可以被訪問的。
ConcreteVisotor---抽象元素
---|他影響訪問者訪問到類后,該怎么做,要做什么事情。
Element---抽象元素
--|接口或者抽象類,聲明接受哪一類訪問者訪問,程序上通過accept方法中的參數定義
ConcreteElement---具體元素
--|實現accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。
ObjectStruture---結構對象
--|元素產生者,一般容納在多個不同類、不同接口的容器,如List、Set、Map等,在項目中,一般很少抽象出這個角色。
~~~
public class VisitorTest {
public static void main(String[] args) {
//產生10個具體元素對象
for(int i=0;i<10;i++){
Element e = ObjectStruture.createElement();
//接收訪問者訪問
e.accept(new ConcreteVisitor());
}
}
}
/**
* 抽象元素類
* 除了有自己的業務邏輯外,
* 定義哪一類的訪問者,可以訪問。
* @author admin
*
*/
abstract class Element{
//執行自身的業務邏輯
public abstract void doSomenthing();
//定義訪問者都有哪些
public abstract void accept(IVisitor visitor);
}
/**
* 具體的實現元素類。
* 1、實現自身的具體業務邏輯
* 2、設置哪個訪問者可以訪問
* @author admin
*
*/
class ConcreteElement1 extends Element{
@Override
public void doSomenthing() {
System.out.println("我是元素1的具體實現者...");
}
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
/**
* 具體的實現元素類。
* 1、實現自身的具體業務邏輯
* 2、設置哪個訪問者可以訪問
* @author admin
*
*/
class ConcreteElement2 extends Element{
@Override
public void doSomenthing() {
System.out.println("我是元素2的具體實現者...");
}
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
/**
* 抽象訪問者,
* 聲明訪問者可以訪問哪些類。具體的執行方法有子類去實現
* @author admin
*
*/
interface IVisitor{
//定義訪問ConcreteElement1類的具體實現
public void visit(ConcreteElement1 con1);
//定義訪問ConcreteElement2類的具體實現
public void visit(ConcreteElement2 con2);
}
/**
* 訪問者的具體實現類,
* 訪問者訪問到類以后,做什么事情,有該類來具體實現
* @author admin
*
*/
class ConcreteVisitor implements IVisitor{
@Override
public void visit(ConcreteElement1 con1) {
con1.doSomenthing();
System.out.println("----訪問者1號,執行任務");
}
@Override
public void visit(ConcreteElement2 con2) {
con2.doSomenthing();
System.out.println("----訪問者2號,執行任務");
}
}
/**
* 元素的產生者,用于產生被訪問者類型的對象。
* @author admin
*
*/
class ObjectStruture{
//利用一個隨機數,產生實現類1和2的對象
public static Element createElement(){
Random random = new Random();
if(random.nextInt(100)>50){
return new ConcreteElement1();
}
return new ConcreteElement2();
}
}
~~~
## 一個例子
一個公司有普通員工和經理,他們都有:姓名、性別、薪水。
私有屬性:員工:job(工作),經理:performance(業績)。
這里需要打印一堆報表,要求員工和經理的相互區分。如何設計合理呢?
~~~
public class VisitorT {
public static void main(String[] args) {
//打印公司員工的報表
for(Emploee e : mockEmploy()){
e.accept(new EmployeeVisitor());
}
}
//模擬公司所有的人員。
public static List<Emploee> mockEmploy(){
List<Emploee> employeeList = new ArrayList<Emploee>();
//創建一些普通員工
Employer common1 = new Employer();
common1.setName("lz");
common1.setJob("APP應用上市..");
common1.setSalary(12000);
common1.setSex(1);
Employer common2 = new Employer();
common2.setName("ly");
common2.setJob("APP應用上市..");
common2.setSalary(11000);
common2.setSex(1);
Employer common3 = new Employer();
common3.setName("ht");
common3.setJob("美工做好..");
common3.setSalary(10000);
common3.setSex(2);
//定義一個經理
Manager m = new Manager();
m.setName("lzl");
m.setPerformence("今天晚上一定加班...");
m.setSalary(1000000);
m.setSex(1);
//添加
employeeList.add(common3);
employeeList.add(common1);
employeeList.add(common2);
employeeList.add(m);
return employeeList;
}
}
/**
* 抽象的員工報表類,
* 定義共有的屬性方法。
* 并提供一個觀察者類的接口
* @author admin
*
*/
abstract class Emploee{
private String name;
private int sex;
private double salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public abstract void accept(IEmployeeVisitor visitor);
}
/**
* 經理類的具體實現類。
* @author admin
*
*/
class Manager extends Emploee{
//經理關注的是公司業績
private String performence;
public String getPerformence() {
return performence;
}
public void setPerformence(String performence) {
this.performence = performence;
}
@Override
public void accept(IEmployeeVisitor visitor) {
visitor.visit(this);
}
}
/**
* 普通員工的具體實現類。
* @author admin
*/
class Employer extends Emploee{
//普工關注的是工作
private String job;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public void accept(IEmployeeVisitor visitor) {
visitor.visit(this);
}
}
/**
* 報表觀察者接口類,
* 設置觀察者觀察具體的實現類。
* 具體的實現方法,由實現類來完成
* @author admin
*
*/
interface IEmployeeVisitor{
//設置觀察普通員工
public void visit(Employer employer);
//設置觀察經理
public void visit(Manager manager);
}
/**
* 具體的觀察者實現類,
* 實現類中觀察到被觀察者,之后需要打印報表。
* @author admin
*
*/
class EmployeeVisitor implements IEmployeeVisitor{
@Override
public void visit(Employer employer) {
System.out.println(this.getEmployerInfo(employer));
}
@Override
public void visit(Manager manager) {
System.out.println(this.getManageInfo(manager));
}
//獲取員工的基本共有信息
private String getBaseInfo(Emploee e){
String info = "姓名:"+e.getName()+"\t性別:"+
(e.getSex()==1 ? "男" : "女")+"\t薪水:"+e.getSalary();
return info;
}
//獲取經理的所有信息
private String getManageInfo(Manager m){
String info = m.getPerformence();
return info+"\t"+getBaseInfo(m);
}
//獲取普通員工的全部信息
private String getEmployerInfo(Employer e){
String info = e.getJob();
return info+"\t"+getBaseInfo(e);
}
}
~~~
訪問者模式的擴展
---|統計功能
~~~
interface IEmployeeVisitor{
//設置觀察普通員工
public void visit(Employer employer);
//設置觀察經理
public void visit(Manager manager);
//統計薪水功能
public void totalSalary();
}
/**
* 具體的觀察者實現類,
* 實現類中觀察到被觀察者,之后需要打印報表。
* @author admin
*
*/
class EmployeeVisitor implements IEmployeeVisitor{
//經理總共薪資
private double totalManager=0;
//普通員工薪資
private double totalEmployer=0;
@Override
public void visit(Employer employer) {
this.getEmployer(employer);
}
@Override
public void visit(Manager manager) {
this.getManagerSalary(manager);
}
//統計總共的薪水
@Override
public void totalSalary() {
System.out.println( "公司一年支付的薪水是:"+this.totalEmployer + this.totalManager);
}
//統計經理的薪水
private void getManagerSalary(Manager m){
this.totalManager = this.totalManager + m.getSalary();
}
//統計員工的薪水
private void getEmployer(Employer e){
this.totalEmployer = this.totalEmployer + e.getSalary();
}
}
~~~
**訪問者模式的優點:**
符合單一職責原則
優秀的擴展性
靈活性非常高
**訪問者模式的缺點:**
具體元素對訪問者公布細節
具體元素變更比較困難
違背了依賴倒置原則
- 前言
- 6大設計原則(一)---單一職責原則
- 6大設計原則(二)---里氏替換原則
- 6大設計原則(三)---依賴倒置原則
- 6大設計模式(四)----接口隔離原則
- 6大設計原則(五)---迪米特法則
- 6大設計原則(六)---開閉原則。
- 設計模式(一)---單例模式
- 設計模式(二)---工廠方法模式
- 設計模式(三)---抽象工廠模式
- 設計模式(四)---模板方法模式
- 設計模式(五)---建造者模式
- 設計模式(六)---代理模式
- 設計模式(七)---原型模式
- 設計模式(八)---中介者模式
- 設計模式(九)---命令模式
- 設計模式(十)---責任鏈模式
- 設計模式(十一)---裝飾模式
- 設計模式(十二)---策略模式
- 設計模式(十三)---適配器模式
- 設計模式(十四)---迭代器模式
- 設計模式(十五)---組合模式
- 設計模式(十六)---觀察者模式
- 設計模式(十七)---門面模式
- 設計模式(十八)---備忘錄模式
- 設計模式(十八)---訪問者模式
- 設計模式(二十)---狀態模式
- 設計模式(二十二)---享元模式
- 設計模式(二十三)---橋梁模式