最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java設(shè)計(jì)模式之訪問(wèn)者模式

 更新時(shí)間:2022年10月21日 08:41:21   作者:tianClassmate  
這篇文章介紹了Java設(shè)計(jì)模式之訪問(wèn)者模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

大多數(shù)情況下你不需要訪問(wèn)者模式,但當(dāng)一旦需要訪問(wèn)者模式時(shí),那就是真的需要它了,這是設(shè)計(jì)模式創(chuàng)始人的原話??梢钥闯鰬?yīng)用場(chǎng)景比較少,但需要它的時(shí)候是不可或缺的,這篇文章就開(kāi)始學(xué)習(xí)最后一個(gè)設(shè)計(jì)模式——訪問(wèn)者模式。

一、概念理解

訪問(wèn)者模式概念:封裝作用于某對(duì)象結(jié)構(gòu)中的各元素的操作,它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

通俗的解釋就是,系統(tǒng)中有一些固定結(jié)構(gòu)的對(duì)象(元素),在其內(nèi)部提供一個(gè)accept()方法用來(lái)接受訪問(wèn)者對(duì)象的訪問(wèn),不同的訪問(wèn)者對(duì)同一元素的訪問(wèn)內(nèi)容不同,所以使得相同的元素可以產(chǎn)生不同的元素結(jié)果。

比如在一個(gè)人事管理系統(tǒng)中,有多個(gè)工種的員工和多個(gè)老板,不同的老板對(duì)同一個(gè)員工的關(guān)注點(diǎn)是不同的,CTO可能關(guān)注的就是技術(shù),CEO可能更注重績(jī)效。

員工就是一個(gè)穩(wěn)定的元素,老板就是變化的,對(duì)應(yīng)概念就是:封裝員工的一些操作,可以在不改變員工類的前提下,增加新的老板訪問(wèn)同一個(gè)員工。

在訪問(wèn)者模式中包含五個(gè)角色,抽象元素、具體元素、抽象訪問(wèn)者、具體訪問(wèn)者、結(jié)構(gòu)元素。

抽象元素:定義一個(gè)接受訪問(wèn)的方法accept,參數(shù)為訪問(wèn)者對(duì)象。

具體元素:提供接受訪問(wèn)者訪問(wèn)的具體實(shí)現(xiàn)調(diào)用訪問(wèn)者的訪問(wèn)visit,并定義額外的數(shù)據(jù)操作方法。

抽象訪問(wèn)者:這個(gè)角色主要是定義對(duì)具體元素的訪問(wèn)方法visit,理論上來(lái)說(shuō)方法數(shù)等于元素(固定類型的對(duì)象,也就是被訪問(wèn)者)個(gè)數(shù)。

具體訪問(wèn)者:實(shí)現(xiàn)對(duì)具體元素的訪問(wèn)visit方法,參數(shù)就是具體元素。

結(jié)構(gòu)對(duì)象:創(chuàng)建一個(gè)數(shù)組用來(lái)維護(hù)元素,并提供一個(gè)方法訪問(wèn)所有的元素。

二、案例實(shí)現(xiàn)

在一個(gè)公司有干活的工程師和管理者,也有抓技術(shù)的CTO和管績(jī)效的CEO,CTO和CEO都會(huì)訪問(wèn)管理員和工程師,當(dāng)公司來(lái)了新的老板,只需要增加訪問(wèn)者即可。

工程師和管理者就是元素、公司就是結(jié)構(gòu)體、CEO、CTO就是訪問(wèn)者。

抽象元素:

/**
 *  員工 抽象元素 被訪問(wèn)者
 * @author tcy
 * @Date 29-09-2022
 */
public interface ElementAbstract {
    void accept(VisitorAbstract visitor);
}

具體元素-工程師:

/**
 * 工程師 具體元素 被訪問(wèn)者
 * @author tcy
 * @Date 29-09-2022
 */
public class ElementEngineer implements ElementAbstract {

    private String name;

    private int kpi;

    ElementEngineer(String name){
        this.name = name;
        this.kpi = new Random().nextInt(10);
    }

    public String getName() {
        return name;
    }

    public int getKpi() {
        return kpi;
    }


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

    public int getCodeLineTotal(){
        return this.kpi * 1000000;
    }
}

具體元素-管理者:

/**
 * 管理者 具體元素 被訪問(wèn)者
 * @author tcy
 * @Date 29-09-2022
 */
public class ElementManager implements ElementAbstract {
    private String name;

    private int kpi;

    ElementManager(String name){
        this.name = name;
        this.kpi = new Random().nextInt(10);
    }

    public String getName() {
        return name;
    }

    public int getKpi() {
        return kpi;
    }

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

    public int getProductNum(){
        return this.kpi * 10;
    }

}

抽象訪問(wèn)者:

/**
 * 抽象訪問(wèn)者
 * @author tcy
 * @Date 29-09-2022
 */
public interface VisitorAbstract {
    void visit(ElementEngineer engineer);

    void visit(ElementManager manager);
}

具體訪問(wèn)者-CEO

/**
 * 具體訪問(wèn)者CEO
 * @author tcy
 * @Date 29-09-2022
 */
public class VisitorCEO implements VisitorAbstract {
    @Override
    public void visit(ElementEngineer engineer) {
        System.out.println("工程師:" + engineer.getName() + "KPI:" + engineer.getKpi());
    }

    @Override
    public void visit(ElementManager manager) {
        System.out.println("經(jīng)理:" + manager.getName() + "KPI:" + manager.getKpi() + " 今年共完成項(xiàng)目:" + manager.getProductNum() + "個(gè)");
    }
}

具體訪問(wèn)者-CTO

/**
 * 具體訪問(wèn)者CTO
 * @author tcy
 * @Date 29-09-2022
 */
public class VisitorCTO implements VisitorAbstract {
    @Override
    public void visit(ElementEngineer engineer) {
        System.out.println("工程師:" + engineer.getName() + " 今年代碼量" + engineer.getCodeLineTotal() + "行");
    }

    @Override
    public void visit(ElementManager manager) {
        System.out.println("經(jīng)理:" + manager.getName() + " 今年共完成項(xiàng)目:" + manager.getProductNum() + "個(gè)");
    }
}

結(jié)構(gòu)體:

/**
 * 結(jié)構(gòu)對(duì)象
 * @author tcy
 * @Date 29-09-2022
 */
public class Structure {
    List<ElementAbstract> list = new ArrayList<>();

    public Structure addEmployee(ElementAbstract employee){
        list.add(employee);
        return this;
    }

    public void report(VisitorAbstract visitor){
        list.forEach(employee -> {
            employee.accept(visitor);
        });
    }

}

客戶端:

/**
 * @author tcy
 * @Date 29-09-2022
 */
public class Client {
    public static void main(String[] args) {
        //元素對(duì)象
        ElementEngineer engineerZ = new ElementEngineer("小張");
        ElementEngineer engineerW = new ElementEngineer("小王");
        ElementEngineer engineerL = new ElementEngineer("小李");

        ElementManager managerZ = new ElementManager("張總");
        ElementManager managerW = new ElementManager("王總");
        ElementManager managerL = new ElementManager("李總");

        //結(jié)構(gòu)體對(duì)象
        Structure structure = new Structure();
        structure.addEmployee(engineerZ).addEmployee(engineerW).addEmployee(engineerL).addEmployee(managerZ).addEmployee(managerW).addEmployee(managerL);
        structure.report(new VisitorCTO());
        System.out.println("---------------------------------------");
        structure.report(new VisitorCEO());


    }
}

訪問(wèn)者不愧是最難的設(shè)計(jì)模式,方法間的調(diào)用錯(cuò)綜復(fù)雜,日常開(kāi)發(fā)的使用頻率很低,很多程序員寧可代碼寫(xiě)的麻煩一點(diǎn)也不用這種設(shè)計(jì)模式,但是作為學(xué)習(xí)者就要學(xué)習(xí)各種設(shè)計(jì)模式了。

三、訪問(wèn)者模式在JDk中的應(yīng)用

JDK的NIO中的 FileVisitor 接口采用的就是訪問(wèn)者模式。

在早期的 Java 版本中,如果要對(duì)指定目錄下的文件進(jìn)行遍歷,必須用遞歸的方式來(lái)實(shí)現(xiàn),這種方法復(fù)雜且靈活性不高。

Java 7 版本后,F(xiàn)iles 類提供了 walkFileTree() 方法,該方法可以很容易的對(duì)目錄下的所有文件進(jìn)行遍歷,需要 Path、FileVisitor 兩個(gè)參數(shù)。其中,Path 是要遍歷文件的路徑,F(xiàn)ileVisitor 則可以看成一個(gè)文件訪問(wèn)器,源碼如下。

FileVisitor 主要提供了 4 個(gè)方法,且返回結(jié)果的都是 FileVisitResult 對(duì)象值,用于決定當(dāng)前操作完成后接下來(lái)該如何處理。FileVisitResult 是一個(gè)枚舉類,代表返回之后的一些后續(xù)操作,源碼如下。

FileVisitResult 主要包含 4 個(gè)常見(jiàn)的操作。

  • FileVisitResult.CONTINUE:這個(gè)訪問(wèn)結(jié)果表示當(dāng)前的遍歷過(guò)程將會(huì)繼續(xù)。
  • FileVisitResult.SKIP_SIBLINGS:這個(gè)訪問(wèn)結(jié)果表示當(dāng)前的遍歷過(guò)程將會(huì)繼續(xù),但是要忽略當(dāng)前文件/目錄的兄弟節(jié)點(diǎn)。
  • FileVisitResult.SKIP_SUBTREE:這個(gè)訪問(wèn)結(jié)果表示當(dāng)前的遍歷過(guò)程將會(huì)繼續(xù),但是要忽略當(dāng)前目錄下的所有節(jié)點(diǎn)。
  • FileVisitResult.TERMINATE:這個(gè)訪問(wèn)結(jié)果表示當(dāng)前的遍歷過(guò)程將會(huì)停止。

通過(guò)訪問(wèn)者去遍歷文件樹(shù)會(huì)比較方便,比如查找文件夾內(nèi)符合某個(gè)條件的文件或者某一天內(nèi)所創(chuàng)建的文件,這個(gè)類中都提供了相對(duì)應(yīng)的方法。它的實(shí)現(xiàn)也非常簡(jiǎn)單,代碼如下。

在JDK的應(yīng)用中我們提供的文件就看做是一個(gè)穩(wěn)定元素,對(duì)應(yīng)訪問(wèn)者模式中的抽象元素;而Files.walkFileTree()方法中的FileVisitor 參數(shù)就可看做是角色中的訪問(wèn)者。

四、訪問(wèn)者模式中的偽動(dòng)態(tài)雙分派

訪問(wèn)者模式中有一個(gè)重要的概念叫:偽動(dòng)態(tài)雙分派。

我們一步一步解讀它的含義,什么叫分派?根據(jù)對(duì)象的類型而對(duì)方法進(jìn)行的選擇,就是分派(Dispatch)。

發(fā)生在編譯時(shí)的分派叫靜態(tài)分派,例如重載(overload),發(fā)生在運(yùn)行時(shí)的分派叫動(dòng)態(tài)分派,例如重寫(xiě)(overwrite)。

其中分派又分為單分派和多分派。

單分派:依據(jù)單個(gè)變量進(jìn)行方法的選擇就叫單分派,Java 動(dòng)態(tài)分派(重寫(xiě))只根據(jù)方法的接收者一個(gè)變量進(jìn)行分配,所以其是單分派。

多分派:依據(jù)多個(gè)變量進(jìn)行方法的選擇就叫多分派,Java 靜態(tài)分派(重載)要根據(jù)方法的接收者與參數(shù)這兩個(gè)變量進(jìn)行分配,所以其是多分派。

理解了概念我們接著看我們的案例:

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

我們案例中的accept方法,是由元素的運(yùn)行時(shí)類型決定的,應(yīng)該是屬于動(dòng)態(tài)單分派。

我們接著看 visitor.visit(this)又是一次動(dòng)態(tài)單分派,兩次動(dòng)態(tài)單分派實(shí)現(xiàn)了雙分派的效果,所以稱為偽動(dòng)態(tài)雙分派。

這個(gè)概念理解就好,實(shí)際應(yīng)用中知不知道這玩意都不影響。

五、總結(jié)

當(dāng)你有個(gè)類,里面的包含各種類型的元素,這個(gè)類結(jié)構(gòu)比較穩(wěn)定,不會(huì)經(jīng)常增刪不同類型的元素。而需要經(jīng)常給這些元素添加新的操作的時(shí)候,考慮使用此設(shè)計(jì)模式。

適用對(duì)象結(jié)構(gòu)比較穩(wěn)定每增加一個(gè)元素訪問(wèn)者都要大變動(dòng),但加新的操作很簡(jiǎn)單。集中相關(guān)的操作、分離無(wú)關(guān)的操作。

缺點(diǎn)只有兩個(gè)字-復(fù)雜,號(hào)稱是最復(fù)雜的設(shè)計(jì)模式。

到此這篇關(guān)于Java設(shè)計(jì)模式之訪問(wèn)者模式的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Boot 自定義starter的示例代碼

    Spring Boot 自定義starter的示例代碼

    這篇文章主要介紹了Spring Boot 自定義starter的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • Java線程池由淺入深掌握到精通

    Java線程池由淺入深掌握到精通

    什么是線程池?很簡(jiǎn)單,簡(jiǎn)單看名字就知道是裝有線程的池子,我們可以把要執(zhí)行的多線程交給線程池來(lái)處理,和連接池的概念一樣,通過(guò)維護(hù)一定數(shù)量的線程池來(lái)達(dá)到多個(gè)線程的復(fù)用
    2021-09-09
  • java中for循環(huán)刪除集合陷阱

    java中for循環(huán)刪除集合陷阱

    java中在增強(qiáng)for循環(huán)為什么不能增刪集合呢?一個(gè)循環(huán)迭代,跟集合的增刪改沒(méi)什么關(guān)系。修改集合不是for去做的。for只管循環(huán)迭代,你在循環(huán)里邊修改集合,改變集合的長(zhǎng)度,順序?qū)ρh(huán)都有影響
    2015-05-05
  • SpringBoot集成Tess4J實(shí)現(xiàn)OCR的示例代碼

    SpringBoot集成Tess4J實(shí)現(xiàn)OCR的示例代碼

    Tess4J是一個(gè)基于Tesseract OCR引擎的Java接口,可以用來(lái)識(shí)別圖像中的文本,說(shuō)白了,就是封裝了它的API,讓Java可以直接調(diào)用,本文給大家介紹了SpringBoot集成Tess4J實(shí)現(xiàn)OCR的示例,需要的朋友可以參考下
    2024-12-12
  • 舉例講解Java設(shè)計(jì)模式中的對(duì)象池模式編程

    舉例講解Java設(shè)計(jì)模式中的對(duì)象池模式編程

    這篇文章主要介紹了Java設(shè)計(jì)模式中的對(duì)象池模式編程示例分享,對(duì)象池模式經(jīng)常在多線程開(kāi)發(fā)時(shí)被用到,需要的朋友可以參考下
    2016-02-02
  • Java中List集合的常用方法詳解

    Java中List集合的常用方法詳解

    本篇文章給大家?guī)?lái)的內(nèi)容是關(guān)于Java中List集合的常用方法詳解,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。下面我們就來(lái)學(xué)習(xí)一下吧
    2021-11-11
  • Idea配置熱部署的詳細(xì)教程

    Idea配置熱部署的詳細(xì)教程

    這篇文章主要介紹了Idea配置熱部署的詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java添加Word文本水印和圖片水印

    Java添加Word文本水印和圖片水印

    這篇文章主要介紹了Java添加Word文本水印和圖片水印,文章圖文講解的很清晰,有對(duì)于這方面不懂得同學(xué)可以學(xué)習(xí)下
    2021-02-02
  • SpringBoot中事務(wù)失效的原因詳解

    SpringBoot中事務(wù)失效的原因詳解

    這篇文章主要介紹了SpringBoot中事務(wù)失效的原因詳解,spring中的事務(wù)是依賴AOP的,AOP是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,只有通過(guò)代理類訪問(wèn)的方法才能被攔截,需要的朋友可以參考下
    2023-10-10
  • SpringBoot優(yōu)化接口響應(yīng)時(shí)間的九個(gè)技巧

    SpringBoot優(yōu)化接口響應(yīng)時(shí)間的九個(gè)技巧

    在實(shí)際開(kāi)發(fā)中,提升接口響應(yīng)速度是一件挺重要的事,特別是在面臨大量用戶請(qǐng)求的時(shí)候,本文為大家整理了9個(gè)SpringBoot優(yōu)化接口響應(yīng)時(shí)間的技巧,希望對(duì)大家有所幫助
    2024-01-01

最新評(píng)論

黄山市| 炎陵县| 彭阳县| 神木县| 都江堰市| 西峡县| 广平县| 岳西县| 仪陇县| 灵丘县| 卫辉市| 龙州县| 轮台县| 崇礼县| 巢湖市| 普宁市| 托克托县| 陈巴尔虎旗| 碌曲县| 如皋市| 淮南市| 固镇县| 阳原县| 观塘区| 昭通市| 赤壁市| 大姚县| 马鞍山市| 浦江县| 苍南县| 泽州县| 沾益县| 丽水市| 且末县| 灌阳县| 金山区| 都匀市| 赣州市| 沾益县| 乌审旗| 神农架林区|