访问者模式

5次阅读

共计 2198 个字符,预计需要花费 6 分钟才能阅读完成。

简介

访问者模式,表示一个对于容器中各对象的操作,它让你可以在不改变容器总对象的情况下定义一个新的操作。

UML 类图

示例

学校里有操场,教室,访问者可以为学生和老师,学生在教室学习,老师在教课,学生在操场玩耍,老师在监督,各个类请先自己思考。实现如下
访问者相关类,visitor.h

#ifndef VISITOR_H
#define VISITOR_H
#include <list>

using namespace std;
class CClassroom;
class CPlayground;

class CVisitor
{
public:
    virtual void Visit(CClassroom* pClassroom) = 0;
    virtual void Visit(CPlayground* pPlayground) = 0;
};

class CStudent:public CVisitor
{
public:
    void Visit(CClassroom* pClassroom)  ;
    void Visit(CPlayground* pPlayground)  ;
};

class CTeacher:public CVisitor
{
public:
    void Visit(CClassroom* pClassroom)  ;
    void Visit(CPlayground* pPlayground)  ;
};

class CPlace
{
public:
    virtual void accept(CVisitor* pVisitor) = 0;
};

class CClassroom:public CPlace
{
public:
    void accept(CVisitor* pVisitor);
};

class CPlayground:public CPlace
{
public:
    void accept(CVisitor* pVisitor);
};

class CSchool
{
public:
    void Add(CPlace* pPlace);
    void Remove(CPlace* pPlace);
    void Accept(CVisitor* pVisitor);
private:
    list<CPlace*> m_placeContainer;
};
#endif

访问者相关类的实现,visitor.cpp

#include "visitor.h"
#include <iostream>

using namespace std;
void CStudent::Visit(CClassroom* pClassroom)
{cout<<"I'm learning here."<<endl;}

void CStudent::Visit(CPlayground* pPlayground)
{cout<<"I'm playing here."<<endl;}

void CTeacher::Visit(CClassroom* pClassroom)
{cout<<"I'm teaching here."<<endl;}

void CTeacher::Visit(CPlayground* pPlayground)
{cout<<"I'm watching here."<<endl;}

void CClassroom::accept(CVisitor* pVisitor)
{pVisitor->Visit(this);
}

void CPlayground::accept(CVisitor* pVisitor)
{pVisitor->Visit(this);
}

void CSchool::Add(CPlace* pPlace)
{m_placeContainer.push_back(pPlace);
}

void CSchool::Remove(CPlace* pPlace)
{m_placeContainer.remove(pPlace);
}

void CSchool::Accept(CVisitor* pVisitor)
{for(list<CPlace*>::iterator iter = m_placeContainer.begin(); iter != m_placeContainer.end(); ++ iter)
    {(*iter)->accept(pVisitor);
    }
}

客户端调用,main.cpp

#include "visitor.h"

#define SAFE_DELETE(p) if(p){delete (p); (p) = NULL;}
int main(int argc, char* argv[])
{
    CSchool *pSchool = new CSchool;
    CPlace* pClassroom = new CClassroom;
    CPlayground* pPlayground = new CPlayground;
    CVisitor* pTeacher = new CTeacher;
    CVisitor* pStudent = new CStudent;
    pSchool->Add(pClassroom);
    pSchool->Add(pPlayground);
    pSchool->Accept(pTeacher);
    pSchool->Accept(pStudent);
    SAFE_DELETE(pStudent);
    SAFE_DELETE(pTeacher);
    SAFE_DELETE(pPlayground);
    SAFE_DELETE(pClassroom);
    SAFE_DELETE(pSchool);
    return 0;
}

正文完
 0

访问者模式

5次阅读

共计 5958 个字符,预计需要花费 15 分钟才能阅读完成。

首先
抽象员工
public abstract class Employee{
// 代表男性
public final static int MALE = 0;
// 代表女性
public final static int FEMALE = 1;
// 有工资
private String name;
// 薪水
private int salary;
// 性别
private int sex;
// get/set
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public int getSex(){
return sex;
}
public void setSex(int sex){
this.sex = sex;
}
// 员工信息输出
public final void report(){
String info = “ 姓名 ” + this.name + “\t”;
info = info + “ 性别 ” + this.sex + “\t”;
info = info + “ 薪水 ” + this.salary + “\t”;
info = info + this.getOtherinfo();
System.out.println(info);
}
// 拼装
protected abstract String getOtherinfo();
}
下面是普通员工
public class CommonEmployee extends Employee{
// 工作内容
private String job;
public String getJob(){
return job;
}
public void setJob(String job){
this.job = job;
}
protected String getOtherinfo(){
return “ 工作: ” + this.job + “\t”;
}
}
管理层
public class Manager extends Employee{
// 职责
private String performance;
public String getPerformance(){
return performance;
}
public void setPerformance(String performance){
this.performance = performance;
}
protected String getOtherinfo(){
return “ 业绩 ” + this.performance + “\t”;
}
}
最后场景
public class Client{
public static void main(String[] args){
for(Employee emp:mockEmployee()){
emp.report();
}
}
public static List mockEmployee(){
List empList = new ArrayList();
// 产生员工
CommonEmployee zhangSan = new CommonEmployee();
zangSan.setJon(“ 编写程序 ”);
zangSan.setName(“ 张三 ”);
zangSan.setSalary(1800);
zangSan.setSex(Employee.MALE);
empList.add(zangSan);
// 产生员工
CommonEmployee liSi = new CommonEmployee();
liSi.setJob(“ 美工 ”);
liSi.setName(“ 李四 ”);
liSi.setSalary(1900);
liSi.setSex(Employee.FEMALE);
empList.add(liSi);
// 产生经理
Manage wangWu = new Manger();
wangWu.setName(“ 王五 ”);
wangWu.setPerformance(“ 负值 ”);
wangWu.setSalary(18750);
wangWu.setSex(Employee.MALE);
empList.add(wangWu);
return empList;
}
}
改造如下
先定义访问者接口
public interface IVisitor{
// 定义普通员工
public void vsit(CommonEmployee commonEmployee);
// 定义访问部门经理
public void visit(Manager manager);
}
访问者实现
public class Visitor implements IVisitor{
// 访问普通员工,打印报表
public void visit(CommonEmployee commonEmployee){
System.out.println(this.getCommonEmployee(commonEmployee));
}
// 访问部门经理
public void visit(Manager manager){
System.out.println(this.getManagerinfo(manager));
}
// 组装基本信息
private String getBasicinfo(Employee employee){
String info = “ 姓名 ” + employee.getName() + “\t”;
info = info + “ 性别 ” + (employee.getSex() == Employee.FEMALE?” 女 ”,” 男 ”);
info = info + “ 薪水 ” + employee.getSalary() + “\t”;
return info;
}
// 组装普通员工信息
private String getCommonEmployee(CommonEmployee commonEmployee){
String basicinfo = this.getBasicinfo(commonEmployee);
String otherinfo = “ 工作 ” + commonEmployee.getJob() + “\t”;
return basicinfo + otherinfo;
}

}
继续书写抽象员工类
public abstract class Employee{
public final static int MALE = 0;
public final static int FEMALE = 1;
// 工资
private String name;
// 薪水
private int salary;
// 性别
private int sec;
// get/set
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public int getSex(){
return sex;
}
public void setSex(int sex){
this.sex = sex;
}
// 定义访问者访问
public abstract void accept(IVisitor visitor);
}
普通员工
public class CommonEmployee extends Employee{
// 工作内容
private String job;
// 获得 job
public String getJon(){
return job;
}
// 设置 job
public void setJob(String job){
this.job = job;
}
// 允许访问者访问
@Override
public void accept(IVsitor visitor){
visitor.visit(this);
}
}
场景类
public class Client{
public static void main(String[] args){
// 开始循环列表
for(Employee emp:mockEmployee()){
// 将访问者传入,此时 accept 将会调用 visit 方法,将 this 传入
emp.accept(new Visitor());
}
}
public static List mockEmployee(){
List empList = new ArrayList();
// 产生员工
CommonEmployee zhangSan = new CommonEmployee();
// 设置属性
zhangSan.setJon(“ 编写程序 ”);
zhangSan.setName(“ 张三 ”);
zhangSan.setSalary(1800);
zhangSan.setSex(Employee.MALE);
empList.add(zhangSan);
// 产生员工
CommonEmployee liSi = new CommonEmployee();
liSi.setJob(“ 美工 ”);
liSi.setSalary(“ 李四 ”);
liSi.setSalary(1900);
liSi.setSex(Employee.FEMALE);
// 入数组
empList.add(liSi);
// 产生经理
Manager wangWu = new Manager();
wangWu.setName(“ 王五 ”);
wangWu.setPerformance(“ 负数 ”);
wangWu.setSalary(18750);
wangWu.setSex(Employee.MALE);
empList.add(wangWu);
return empList;
}
}
扩展
统计功能
汇总和报表,经常使用统计功能。即,一堆计算公式,生产出一个报表。统计公式员工的工资总额
// 定义抽象访问者
public interface IVisitor{
// 定义可以访问的普通员工
public void visit(CommonEmployee commonEmployee);
// 再次定义访问部门经理
public void visit(Manager manager);
// 统计员工工资总和
public int getTotalSalary();
}
定义访问者
// public class Visitor implements IVisitor{
// 这里实现接口
}
最后编写场景类
public class Client{
public static void main(String[] args){
// 定义一个访问者
// 展示报表的访问者
ISVisitor showVisitor = new Visitor();
// 汇总报表的访问者
ITotalVisitor totalVisitor = new TotalVisitor();
// 遍历, 其中 mockEmployee 是从持久层传来的数据
for(Employee emp:mockEmployee()){
// 对数据进行处理,
// 代执行访问着的 visit 方法。由于数据是保存在 emp 的,所以需要将 this 传入
emp.accept(showVisitor);
emp.accept(totalVisitor);
}
System.out.println(“”);
}
}
双分派
单分派:处理一个操作根据请求着的名称和接受到的参数决定静态绑定,动态绑定,依据重载,覆写实现。栗子
// 定义角色接口,实现类
public interface Role{
// 演员扮演的角色
}
public class KungFuRole implements Role{
// 武功第一的角色
}
public class idiotRole implements Role{
// 弱智角色
}
下面定义抽象演员
public abstract class AbsActor{
// 演员能够扮演的角色
public void act(Role role){
// 演员扮演的角色
}
// 扮演功夫戏
public void act(KungFuRole role){
// 扮演功夫戏
}
}
// 青年演员,老年演员
public class YoungActor extends AbsActor{
// 年轻演员喜欢的功夫戏
public void act(KungFuRole role){

}
}
// 老年演员喜欢的功夫戏
public class OldActor extends AbsActor{
// 扮演功夫角色
public void act(KungFuRole role){
// 扮演功夫角色
}
}
编写场景
public class Client{
public static void main(String[] args){
// 定义一个演员
AbsActor actor = new OldActor();
// 定义一个角色
Role role = new KungFuRole();
// 开始演戏
actor.act(role);
actor.act(new KungFuRole());
}
}
重载在编译期间决定要调用那个方法。静态绑定,是重写的时候就断定要绑定那个,例如定义年轻演员的时候,重写的 act 方法,此时为静态绑定了 KungFuRole,动态绑定呢,act 方法,只有在运行的时候才能判断是和那个绑定
一个演员可以扮演多个角色,如何实现呢,使用访问者模式
public interface Role{
// 演员扮演的角色
public void accept(AbstActor actor);
}
public class KungFuRole implements Role{
// 角色
public void accept(Abstract actor){
actor.act(this);
}
}
public class ldiotRole implements Role{
// 弱智角色
public void accept(AbsActor actor){
actor.act(this);
}
}
书写场景类
public class Clicent{
public static void main(String[] args){
// 定义演员
AbsActor actor = new OldActor();
// 定义角色
Role role = new KungFuRole();
// 开始演戏
role.accept(actor);
}
}

总结
在上面的栗子中,角色只有在运行期间才能判断由那个演员执行,演员事先定义和那个角色绑定,所以角色使用接口,演员使用抽象类。
接口,抽象类 接口呢 是在运行的时候才能发现,所以使用动态绑定,抽象类适合使用静态绑定。啊哈,这就是接口和抽象类的区别。
访问者模式的核心在于定义一个方法,就像开启一个门,让访问者进入,然后在将其信息传递给访问者,由访问者执行需要产生的内容。
应用
过滤展示,报表,ui 展示,过滤器,拦截器

正文完
 0