十一、访问者模式

概念

将数据结构和作用于数据结构上的操作分离开来,让新的操作可以在不改变数据结构的前提下添加进来

能够不在类中新增方法,实现对类中数据的操作

应用场景

为对象增加操作方法,但不需要将操作添加到类中

需要对一类不同的对象增加相同的操作,使用访问者方法不需要再每个类中编写操作方法,将操作方法集中管理

基本结构

1)元素接口(Element):这是所有元素的基类或者接口,声明了接受访问者的accept()方法。每个元素类都会实现该方法,用来将访问者传递给自己

2)具体元素(ConcreteElement):每个具体元素类都实现了抽象元素的accept()方法,通常这个方法会将自己传递给访问者,让访问者执行特定的操作

3)访问‏者接口(Visitor):؜定义了针对每个具体元素类的؜操作。每个具体访问⁡者都实现这个接口,并且‍为每个元素类提供不同的操作

4)具体访‏问者(Concre؜teVisitor؜):实现了抽象访问⁡者接口,并为每个具‍体元素提供特定的操作

代码实现

以 ‏“文档格式转换” ؜为例

访问者接口

规定访问者需要实现的方法

public interface DocumentVisitor {
    void visit(PDFDocument pdf);
    void visit(WordDocument word);
    void visit(ExcelDocument excel);
}

元素接口

声明一个accept()方法,使得每个元素能够接受访问者,参数中传入一个访问者,调用访问者实现的visit()方法

public interface Document {
    void accept(DocumentVisitor visitor);
}

具体元素

每个文档类都实现 accept 方法,并在其中调用访问者的对应方法,把自身 this 传过去。这样访问者就可以获取到文档数据并处理,而文档类不需要知道“怎么处理”

public class PDFDocument implements Document {
    private String content;

    public PDFDocument(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
}
public class WordDocument implements Document {
    private String content;

    public WordDocument(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
}
public class ExcelDocument implements Document {
    private String[][] table;

    public ExcelDocument(String[][] table) {
        this.table = table;
    }

    public String[][] getTable() {
        return table;
    }

    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
}

具体访问者

访问者类‏实现了将文档转换为 H؜TML 的具体逻辑。每؜种文档的转换方式不同,⁡但它们共用一个访问者接‍口,使得扩展变得灵活又统一

public class HtmlExportVisitor implements DocumentVisitor {

    @Override
    public void visit(PDFDocument pdf) {
        System.out.println("<html><body><h1>PDF 内容</h1><p>" + pdf.getContent() + "</p></body></html>");
    }

    @Override
    public void visit(WordDocument word) {
        System.out.println("<html><body><h1>Word 内容</h1><p>" + word.getContent() + "</p></body></html>");
    }

    @Override
    public void visit(ExcelDocument excel) {
        System.out.println("<html><body><h1>Excel 内容</h1><table border='1'>");
        for (String[] row : excel.getTable()) {
            System.out.print("<tr>");
            for (String cell : row) {
                System.out.print("<td>" + cell + "</td>");
            }
            System.out.println("</tr>");
        }
        System.out.println("</table></body></html>");
    }
}

客户端调用

具体元素只需接受具体访问者即可调用访问者的方法

public class Client {
    public static void main(String[] args) {
        Document pdf = new PDFDocument("这是 PDF 文件的内容");
        Document word = new WordDocument("这是 Word 文档的内容");
        Document excel = new ExcelDocument(new String[][] {
            {"姓名", "成绩"},
            {"鱼皮", "90"},
            {"Yes哥", "95"}
        });

        DocumentVisitor htmlExporter = new HtmlExportVisitor();

        pdf.accept(htmlExporter);
        word.accept(htmlExporter);
        excel.accept(htmlExporter);
    }
}

优缺点

优点

1)集中操作:将操作集中在访问者类中,避免了在各个元素类中重复实现相同的操作

2)扩展性强:访问者模式可以让我们在不改变元素类(被访问者类)的情况下,增加新的操作

缺点

1)修改元素类困难:虽然增加新操作很方便,但一旦要修改元素类的结构,就会影响到所有的访问者

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇