溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么深入理解Java設(shè)計(jì)模式中的訪問(wèn)者模式

發(fā)布時(shí)間:2021-11-05 17:51:43 來(lái)源:億速云 閱讀:112 作者:柒染 欄目:開(kāi)發(fā)技術(shù)

怎么深入理解Java設(shè)計(jì)模式中的訪問(wèn)者模式,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

一、什么是訪問(wèn)者模式

定義:表示一個(gè)作用于其對(duì)象結(jié)構(gòu)中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用于這些元素的新操作。

可以對(duì)定義這么理解:有這么一個(gè)操作,它是作用于一些元素之上的,而這些元素屬于某一個(gè)對(duì)象結(jié)構(gòu)。同時(shí)這個(gè)操作是在不改變各元素類的前提下,在這個(gè)前提下定義新操作是訪問(wèn)者模式精髓中的精髓。

主要解決:穩(wěn)定的數(shù)據(jù)結(jié)構(gòu)和易變的操作耦合問(wèn)題。就是把數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦合,使得操作集合可相對(duì)自由地演化。

本質(zhì):預(yù)留通路,回調(diào)實(shí)現(xiàn)。它的實(shí)現(xiàn)主要就是通過(guò)預(yù)先定義好調(diào)用的通路,在被訪問(wèn)的對(duì)象上定義accept方法,在訪問(wèn)者的對(duì)象上定義visit方法;然后在調(diào)用真正發(fā)生的時(shí)候,通過(guò)兩次分發(fā)的技術(shù),利用預(yù)先定義好的通路,回調(diào)到訪問(wèn)者具體的實(shí)現(xiàn)上。

二、訪問(wèn)者模式的結(jié)構(gòu)

怎么深入理解Java設(shè)計(jì)模式中的訪問(wèn)者模式

Visitor抽象訪問(wèn)者接口:它定義了對(duì)每一個(gè)元素(Element)訪問(wèn)的行為,它的參數(shù)就是可以訪問(wèn)的元素,它的方法個(gè)數(shù)理論上來(lái)講與元素個(gè)數(shù)(Element的實(shí)現(xiàn)類個(gè)數(shù))是一樣的,從這點(diǎn)不難看出,訪問(wèn)者模式要求元素類的個(gè)數(shù)不能改變(不能改變的意思是說(shuō),如果元素類的個(gè)數(shù)經(jīng)常改變,則說(shuō)明不適合使用訪問(wèn)者模式)。

ConcreteVisitor具體訪問(wèn)者角色:它需要給出對(duì)每一個(gè)元素類訪問(wèn)時(shí)所產(chǎn)生的具體行為。

Element抽象節(jié)點(diǎn)(元素)角色:它定義了一個(gè)接受訪問(wèn)者(accept)的方法,其意義是指,每一個(gè)元素都要可以被訪問(wèn)者訪問(wèn)。

ConcreteElement具體節(jié)點(diǎn)(元素)角色:它提供接受訪問(wèn)方法的具體實(shí)現(xiàn),而這個(gè)具體的實(shí)現(xiàn),通常情況下是使用訪問(wèn)者提供的訪問(wèn)該元素類的方法。

ObjectStructure結(jié)構(gòu)對(duì)象角色:這個(gè)便是定義當(dāng)中所提到的對(duì)象結(jié)構(gòu),對(duì)象結(jié)構(gòu)是一個(gè)抽象表述,具體點(diǎn)可以理解為一個(gè)具有容器性質(zhì)或者復(fù)合對(duì)象特性的類,它會(huì)含有一組元素(Element),并且可以迭代這些元素,供訪問(wèn)者訪問(wèn)。

三、訪問(wèn)者模式的使用場(chǎng)景

(1)對(duì)象結(jié)構(gòu)比較穩(wěn)定,但經(jīng)常需要在此對(duì)象結(jié)構(gòu)上定義新的操作。

(2)需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的對(duì)象進(jìn)行很多不同的且不相關(guān)的操作,而需要避免這些操作“污染”這些對(duì)象的類,也不希望在增加新操作時(shí)修改這些類。

四、訪問(wèn)者模式的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1. 訪問(wèn)者模式使得易于增加新的操作 訪問(wèn)者使得增加依賴于復(fù)雜對(duì)象結(jié)構(gòu)的構(gòu)件的操作變得容易了。僅需增加一個(gè)新的訪問(wèn)者即可在一個(gè)對(duì)象結(jié)構(gòu)上定義一個(gè)新的操作。相反, 如果每個(gè)功能都分散在多個(gè)類之上的話,定義新的操作時(shí)必須修改每一類。

2. 訪問(wèn)者集中相關(guān)的操作而分離無(wú)關(guān)的操作 相關(guān)的行為不是分布在定義該對(duì)象結(jié)構(gòu)的 各個(gè)類上,而是集中在一個(gè)訪問(wèn)者中。無(wú)關(guān)行為卻被分別放在它們各自的訪問(wèn)者子類中。這 就既簡(jiǎn)化了這些元素的類,也簡(jiǎn)化了在這些訪問(wèn)者中定義的算法。所有與它的算法相關(guān)的數(shù) 據(jù)結(jié)構(gòu)都可以被隱藏在訪問(wèn)者中。

缺點(diǎn):

1. 增加新的 ConcreteElement類很困難

Visitor模式使得難以增加新的 Element的子類。每 添加一個(gè)新的 ConcreteElement都要在 Vistor中添加一個(gè)新的抽象操作,并在每一個(gè) ConcretVisitor類中實(shí)現(xiàn)相應(yīng)的操作。有時(shí)可以在 Visitor中提供一個(gè)缺省的實(shí)現(xiàn),這一實(shí)現(xiàn)可 以被大多數(shù)的 ConcreteVisitor繼承,但這與其說(shuō)是一個(gè)規(guī)律還不如說(shuō)是一種例外。

所以在應(yīng)用訪問(wèn)者模式時(shí)考慮關(guān)鍵的問(wèn)題是系統(tǒng)的哪個(gè)部分會(huì)經(jīng)常變化,是作用于對(duì)象結(jié)構(gòu)上的算法呢還是構(gòu)成該結(jié)構(gòu)的各個(gè)對(duì)象的類。如果老是有新的 ConcretElement類加入進(jìn)來(lái)的話, Vistor類層次將變得難以維護(hù)。在這種情況下,直接在構(gòu)成該結(jié)構(gòu)的類中定義這些操作可能更容易一些。如果 Element類層次是穩(wěn)定的,而你不斷地增加操作獲修改算法,訪問(wèn)者模式可以幫助你管理這些改動(dòng)。

2. 破壞封裝

訪問(wèn)者方法假定ConcreteElement接口的功能足夠強(qiáng),足以讓訪問(wèn)者進(jìn)行它 們的工作。結(jié)果是,該模式常常迫使你提供訪問(wèn)元素內(nèi)部狀態(tài)的公共操作,這可能會(huì)破壞它 的封裝性。

五、訪問(wèn)者模式的實(shí)現(xiàn)

抽象訪問(wèn)者角色:為每一個(gè)具體節(jié)點(diǎn)都準(zhǔn)備了一個(gè)訪問(wèn)操作。

//這里由于有兩個(gè)節(jié)點(diǎn),因此,對(duì)應(yīng)就有兩個(gè)訪問(wèn)操作。
public interface Visitor {
    /**
     * 對(duì)應(yīng)于NodeA的訪問(wèn)操作
     */
    public void visit(NodeA node);
    /**
     * 對(duì)應(yīng)于NodeB的訪問(wèn)操作
     */
    public void visit(NodeB node);
}

具體訪問(wèn)者

/**
 * 具體訪問(wèn)者VisitorA類
 */
public class VisitorA implements Visitor {
    /**
     * 對(duì)應(yīng)于NodeA的訪問(wèn)操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 對(duì)應(yīng)于NodeB的訪問(wèn)操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }
}
/**
 * 具體訪問(wèn)者VisitorB類
 */
public class VisitorB implements Visitor {
    /**
     * 對(duì)應(yīng)于NodeA的訪問(wèn)操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 對(duì)應(yīng)于NodeB的訪問(wèn)操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }
}

抽象節(jié)點(diǎn)類

/**
 * 抽象節(jié)點(diǎn)類
 */
public abstract class Node {
    /**
     * 接受操作
     */
    public abstract void accept(Visitor visitor);
}

具體節(jié)點(diǎn)類

/**
 * 具體節(jié)點(diǎn)類NodeA
 */
public class NodeA extends Node {
    /**
     * 接受操作
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeA特有的方法
     */
    public String operationA() {
        return "NodeA";
    }
}
/**
 * 具體節(jié)點(diǎn)類NodeB
 */
public class NodeB extends Node {
    /**
     * 接受方法
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeB特有的方法
     */
    public String operationB() {
        return "NodeB";
    }
}

結(jié)構(gòu)對(duì)象角色類

/**
 * 結(jié)構(gòu)對(duì)象角色類
 * 這個(gè)結(jié)構(gòu)對(duì)象角色持有一個(gè)聚集,并向外界提供add()方法作為對(duì)聚集的管理操作。通過(guò)調(diào)用這個(gè)方法,可以動(dòng)態(tài)地增加一個(gè)新的節(jié)點(diǎn)。
 */
public class ObjectStructure {
    private List<Node> nodes = new ArrayList<Node>();
    /**
     * 執(zhí)行方法操作
     */
    public void action(Visitor visitor) {
        for (Node node : nodes) {
            node.accept(visitor);
        }
    }
    /**
     * 添加一個(gè)新元素
     */
    public void add(Node node) {
        nodes.add(node);
    }
}

客戶端代碼

public static void main(String[] args) {
        //創(chuàng)建一個(gè)結(jié)構(gòu)對(duì)象
        ObjectStructure os = new ObjectStructure();
        //給結(jié)構(gòu)增加一個(gè)節(jié)點(diǎn)
        os.add(new NodeA());
        //給結(jié)構(gòu)增加一個(gè)節(jié)點(diǎn)
        os.add(new NodeB());
        //創(chuàng)建一個(gè)訪問(wèn)者
        Visitor visitor = new VisitorA();
        os.action(visitor);
    }

看完上述內(nèi)容,你們掌握怎么深入理解Java設(shè)計(jì)模式中的訪問(wèn)者模式的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI