中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

鉆井網(wǎng)站建設(shè)電商代運(yùn)營(yíng)一般收多少服務(wù)費(fèi)

鉆井網(wǎng)站建設(shè),電商代運(yùn)營(yíng)一般收多少服務(wù)費(fèi),微博wap版登錄入口,招標(biāo)網(wǎng)與采購網(wǎng)訪問者模式 訪問者模式被稱為是最復(fù)雜的設(shè)計(jì)模式,比較難理解并且使用頻率不高。 在 GoF 的《設(shè)計(jì)模式》?書中,訪問者者模式(Visitor Design Pattern)是這么定義的: Allows for one or more operation to be applied to a set o…

訪問者模式

訪問者模式被稱為是最復(fù)雜的設(shè)計(jì)模式,比較難理解并且使用頻率不高。

在 GoF 的《設(shè)計(jì)模式》?書中,訪問者者模式(Visitor Design Pattern)是這么定義的:

Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.

允許?個(gè)或者多個(gè)操作應(yīng)?到?組對(duì)象上,解耦操作和對(duì)象本?。
訪問者模式是一種將數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作分離的設(shè)計(jì)模式,屬于行為型模式。

訪問者模式的基本思想是: 假設(shè)系統(tǒng)中有一個(gè)由許多對(duì)象構(gòu)成的對(duì)象結(jié)構(gòu)(元素),這些對(duì)象的類都提供一個(gè)accept()方法用來接受訪問者對(duì)象的訪問,不同的訪問者訪問同一對(duì)象可以產(chǎn)生不同的數(shù)據(jù)結(jié)果(訪問者其實(shí)就是一個(gè)擁有visit()方法的接口) 。accept()方法可以接收不同的訪問者對(duì)象,然后在其內(nèi)部將自己(元素)轉(zhuǎn)發(fā)到訪問者對(duì)象的visit()方法內(nèi)。

訪問者模式的核心是解耦數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作,使得對(duì)元素的操作具備良好的擴(kuò)展性??梢酝ㄟ^擴(kuò)展不同的訪問者來實(shí)現(xiàn)對(duì)同一元素集的不同操作。

如果你的系統(tǒng)中只是對(duì)單個(gè)對(duì)象(類)進(jìn)行操作或者對(duì)多個(gè)類進(jìn)行一種操作,那么就沒必要使用訪問者模式了。運(yùn)用訪問者模式是為了方便后續(xù)擴(kuò)展操作類型,在對(duì)對(duì)象集(多個(gè)類對(duì)象)擴(kuò)展操作的時(shí)候可以不需要修改所有類的代碼。

當(dāng)系統(tǒng)中存在類型數(shù)目穩(wěn)定(固定)的一類數(shù)據(jù)結(jié)構(gòu)時(shí),可以通過訪問者模式方便地實(shí)現(xiàn)對(duì)該類型所有數(shù)據(jù)結(jié)構(gòu)的不同操作。

訪問者模式類圖

在這里插入圖片描述

主要包含四個(gè)角色 :
Visitor 抽象訪問者:接口或者抽象類,它定義了對(duì)每一個(gè)可訪問元素(Visitable Element)訪問的行為,它的參數(shù)就是可以訪問的元素,它的方法個(gè)數(shù)理論上來講與元素個(gè)數(shù)(Element的實(shí)現(xiàn)類個(gè)數(shù))是一樣的,從這點(diǎn)不難看出,訪問者模式要求元素類的個(gè)數(shù)不能改變(不能改變的意思是說,如果元素類的個(gè)數(shù)經(jīng)常改變,則說明不適合使用訪問者模式)。
ConcreteVisitor:具體的訪問者,實(shí)現(xiàn)對(duì)每一個(gè)元素的具體操作。
Element 抽象元素:元素接口,它定義了一個(gè)接受訪問者(accept)的方法,其意義是指,每一個(gè)元素都要可以被訪問者訪問。
ConcreteElement:具體的元素類,它提供接受訪問者的具體實(shí)現(xiàn),而這個(gè)具體的實(shí)現(xiàn),通常情況下是調(diào)用訪問者提供的訪問該元素類的方法。

代碼示例

我們使用訪問者模式模擬一個(gè)處理不同類型文件的場(chǎng)景
假設(shè)我們有三類文件,PDF,EXCEL,WORD,我們需要從三種文件中提取信息存到到自己的系統(tǒng)里(假設(shè)需要導(dǎo)入到自己的一個(gè)txt文件),然后還需要對(duì)三類文件都進(jìn)行壓縮等一系列功能

將不同文件類型定義為抽象元素(這是一個(gè)穩(wěn)定的數(shù)據(jù)結(jié)構(gòu)), 對(duì)文件的操作定義為訪問者,代碼如下 :

public abstract class ResourceFile {private String name;protected ResourceFile(String name) {this.name = name;}abstract void accept(Vistor vistor);}
public class PDFFile extends ResourceFile {protected PDFFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}public class ExcelFile extends ResourceFile{protected ExcelFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}public class WordFile extends ResourceFile{public WordFile(String name) {super(name);}@Overridevoid accept(Vistor vistor) {vistor.visit(this);}
}
public interface Vistor {void visit(PDFFile file);void visit(ExcelFile file);void visit(WordFile file);}
public class CompressionVistor implements Vistor{@Overridepublic void visit(PDFFile file) {System.out.println("壓縮pdf文件");}@Overridepublic void visit(ExcelFile file) {System.out.println("壓縮excel文件");}@Overridepublic void visit(WordFile file) {System.out.println("壓縮word文件");}
}
public class ExtractVistor implements Vistor{@Overridepublic void visit(PDFFile file) {System.out.println("提取pdf文字內(nèi)容");}@Overridepublic void visit(ExcelFile file) {System.out.println("提取excel文字內(nèi)容");}@Overridepublic void visit(WordFile file) {System.out.println("提取word文字內(nèi)容");}
}
public class Test {private static final List<ResourceFile> resourceFileList = new ArrayList<>();static {resourceFileList.add(new PDFFile("設(shè)計(jì)模式.pdf"));resourceFileList.add(new ExcelFile("Data.excel"));resourceFileList.add(new WordFile("筆記.doc"));}public static void main(String[] args) {for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new CompressionVistor());}for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new ExtractVistor());}}}

Double Dispatch

靜態(tài)分派

靜態(tài)分派(Static Dispatch)就是按照變量的靜態(tài)類型(變量被聲明時(shí)的類型)進(jìn)行分派,從而確定方法的執(zhí)行版本,靜態(tài)分派在編譯時(shí)就可以確定方法的版本,典型例子就是java的方法重載
java在靜態(tài)分派的時(shí)候,我們可以根據(jù)多個(gè)判斷依據(jù)(即參數(shù)個(gè)數(shù)和參數(shù)類型)判斷使用哪個(gè)方法,所以java是靜態(tài)多分派的語言

動(dòng)態(tài)分派

動(dòng)態(tài)分派,不是在編譯期確定方法版本,而是在運(yùn)行時(shí)才能確定

Single Dispatch,指的是我們僅僅需要根據(jù)對(duì)象運(yùn)行時(shí)的類型來決定執(zhí)行哪個(gè)對(duì)象的方法

Double Dispatch,指的是我們需要根據(jù)對(duì)象的運(yùn)行時(shí)類型和參數(shù)的運(yùn)行時(shí)類型來決定執(zhí)行哪個(gè)對(duì)象的哪個(gè)方法 (二者區(qū)別主要在于是否可以根據(jù)方法參數(shù)運(yùn)行時(shí)的類型來判斷執(zhí)行對(duì)象的哪個(gè)方法)

當(dāng)前主流的?向?qū)ο缶幊陶Z?(?如,Java、C++、C#)都只?持 Single Dispatch,不?持 Double Dispatch。

以Java為例,Java?持多態(tài),代碼可以在運(yùn)?時(shí)獲得對(duì)象的實(shí)際類型,然后根據(jù)實(shí)際類型決定調(diào)?哪個(gè)對(duì)象的方法。 Java 也?持方法重載,但 Java 設(shè)計(jì)的方法重載的語法規(guī)則是在編譯時(shí),根據(jù)傳遞進(jìn)函數(shù)的參數(shù)的聲明類型,來決定調(diào)?哪個(gè)重載方法。也就是說,具體執(zhí)?哪個(gè)對(duì)象的哪個(gè)?法,只跟對(duì)象的運(yùn)?時(shí)類型有關(guān),跟參數(shù)的運(yùn)?時(shí)類型?關(guān)。所以,Java 語?是 動(dòng)態(tài)單分派的語言。

我們可以看下具體的例子 :

public class ParentClass {public void method() {System.out.println("ParentClass 執(zhí)行method方法");}}public class SonClass extends ParentClass{@Overridepublic void method() {System.out.println("SonClass 執(zhí)行method方法");}
}
public class SingleDispatch {public void method(ParentClass parentClass) {parentClass.method();}public void print(ParentClass parentClass) {System.out.println("打印parentClass");}public void print(SonClass sonClass) {System.out.println("打印sonClass");}
}
public class Test {public static void main(String[] args) {ParentClass s = new SonClass();SingleDispatch singleDispatch = new SingleDispatch();singleDispatch.method(s);//執(zhí)?哪個(gè)對(duì)象的?法,由對(duì)象的實(shí)際類型決定(多態(tài))singleDispatch.print(s);//執(zhí)?對(duì)象的哪個(gè)?法,由參數(shù)對(duì)象的聲明類型決定,這里聲明的時(shí)ParentClass類型}}

在這里插入圖片描述

動(dòng)態(tài)雙分派的語言不需要訪問者模式

假設(shè) Java 語??持 動(dòng)態(tài)雙分派,那么下面的代碼就可以編譯通過,正常執(zhí)行了。

public class ExtractExecutor {public void extract(PDFFile file) {System.out.println("提取pdf文字內(nèi)容");}public void extract(WordFile file) {System.out.println("提取word文字內(nèi)容");}public void extract(ExcelFile file) {System.out.println("提取excel文字內(nèi)容");}}
    public static void main(String[] args) {ExtractExecutor extractExecutor = new ExtractExecutor();for (ResourceFile resourceFile: resourceFileList) {//這里會(huì)編譯報(bào)錯(cuò): Cannot resolve method 'extract(ResourceFile)'extractExecutor.extract(resourceFile);}}

代碼會(huì)在運(yùn)?時(shí),根據(jù)參數(shù)(resourceFile)的實(shí)際類型(PDFFile、ExcelFile、WordFile),來決定調(diào)用extract()的三個(gè)重載方法中的哪?個(gè),也就不需要訪問者模式了。

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

所謂的動(dòng)態(tài)雙分派就是在運(yùn)行時(shí)根據(jù)對(duì)象和參數(shù)的運(yùn)行時(shí)類型去判斷調(diào)用哪個(gè)一個(gè)對(duì)象的哪個(gè)方法。訪問者模式通過進(jìn)行兩次動(dòng)態(tài)單分派來達(dá)到這個(gè)效果。

for (ResourceFile resourceFile: resourceFileList) {resourceFile.accept(new ExtractVistor());}
  @Overridevoid accept(Vistor vistor) {vistor.visit(this);}

當(dāng)調(diào)用accept()方法的時(shí)候, 根據(jù)resourceFile的實(shí)際類型決定調(diào)用哪個(gè)文件的accept()方法;
在執(zhí)行accept()方法的時(shí)候,根據(jù)vistor的示例類型來決定調(diào)用哪個(gè)Vistor的visist方法,此時(shí)的this的類型就是這個(gè)類的靜態(tài)類型,這是在編譯期就確定的,所以也可以確定是調(diào)用的哪個(gè)重載方法

通過工廠模式實(shí)現(xiàn)上述功能

上述的例子,如果對(duì)文件的操作也比較固定,也可以使用工廠模式來實(shí)現(xiàn),定義?個(gè)包含 extract() 接?的Executor接?。PdfExtractExecutor、ExcelExtractExecutor、WordExtractExecutor 類實(shí)現(xiàn) Executor接?,完成對(duì)各自?件的?本內(nèi)容抽取。然后再提供一個(gè)ExtractExecutorFactory ??類根據(jù)不同的?件類型,返回不同的 Executor。

public abstract class ResourceFile {private String name;protected ResourceFile(String name) {this.name = name;}abstract String getType();
}
public class PDFFile extends ResourceFile {protected PDFFile(String name) {super(name);}@OverrideString getType() {return "PDF";}}
public interface Executor {void extract(ResourceFile file);
}
//省略了WordExtractExecutor,ExcelExtractExecutor的代碼
public class PDFExtractExecutor implements Executor{@Overridepublic void extract(ResourceFile file) {System.out.println("提取pdf的內(nèi)容");}
}
public class ExtractExecutorFactory {private static Map<String, Executor> map = new HashMap<>();static {map.put("PDF", new PDFExtractExecutor());
//        map.put("EXCEL", new ExeclExtractExecutor());
//        map.put("WORD", new WordExtractExecutor());}public static Executor getExecutor(ResourceFile file) {return map.get(file.getType());}}

訪問者模式在源碼中的應(yīng)用

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

package java.nio.file;
public final class Files {...public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)throws IOException{return walkFileTree(start,EnumSet.noneOf(FileVisitOption.class),Integer.MAX_VALUE,visitor);}...
}

FileVisitor 提供了遞歸遍歷文件樹的支持,這個(gè)接口的方法表示了遍歷過程中的關(guān)鍵過程,允許在文件被訪問、目錄將被訪問、目錄已被訪問、發(fā)生錯(cuò)誤等過程中進(jìn)行控制。換句話說,這個(gè)接口在文件被訪問前、訪問中和訪問后,以及產(chǎn)生錯(cuò)誤的時(shí)候都有相應(yīng)的鉤子程序進(jìn)行處理。

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

package java.nio.file;import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;
public interface FileVisitor<T> {FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)throws IOException;FileVisitResult visitFile(T file, BasicFileAttributes attrs)throws IOException;FileVisitResult visitFileFailed(T file, IOException exc)throws IOException;FileVisitResult postVisitDirectory(T dir, IOException exc)throws IOException;
}package java.nio.file;public enum FileVisitResult {CONTINUE,TERMINATE,SKIP_SUBTREE,SKIP_SIBLINGS;
}

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

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

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

public class SimpleFileVisitor<T> implements FileVisitor<T> {protected SimpleFileVisitor() {}@Overridepublic FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)throws IOException{Objects.requireNonNull(dir);Objects.requireNonNull(attrs);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFile(T file, BasicFileAttributes attrs)throws IOException{Objects.requireNonNull(file);Objects.requireNonNull(attrs);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFileFailed(T file, IOException exc)throws IOException{Objects.requireNonNull(file);throw exc;}@Overridepublic FileVisitResult postVisitDirectory(T dir, IOException exc)throws IOException{Objects.requireNonNull(dir);if (exc != null)throw exc;return FileVisitResult.CONTINUE;}
}

一開始覺得這里的設(shè)計(jì)比較多余,后來仔細(xì)想了下,在不同場(chǎng)景下我們對(duì)文件樹的遍歷要求是不一樣的,通過訪問者模式,用戶可以方便的定義自己的遍歷操作

比方說在JavacPathFileManager里就重寫了preVisitDirectoryvisitFile方法

    Files.walkFileTree(packageDir, opts, maxDepth,new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {Path name = dir.getFileName();if (name == null || SourceVersion.isIdentifier(name.toString())) // JSR 292?return FileVisitResult.CONTINUE;elsereturn FileVisitResult.SKIP_SUBTREE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {if (attrs.isRegularFile() && kinds.contains(getKind(file.getFileName().toString()))) {JavaFileObject fe =PathFileObject.createDirectoryPathFileObject(JavacPathFileManager.this, file, pathDir);results.append(fe);}return FileVisitResult.CONTINUE;}});

總結(jié)

簡(jiǎn)單來說,訪問者模式就是封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新操作。

訪問者模式適用場(chǎng)景 :

  1. 數(shù)據(jù)結(jié)構(gòu)穩(wěn)定,但是作用于數(shù)據(jù)結(jié)構(gòu)的操作經(jīng)常變化
  2. 需要數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離
  3. 需要對(duì)不同數(shù)據(jù)類型(元素)進(jìn)行操作,但是有不使用if.. else ..判斷具體類型

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

  1. 使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦,使得操作集合可以獨(dú)立變化。
  2. 擴(kuò)展性好,添加新的操作或者說訪問者會(huì)非常容易。

缺點(diǎn):

  1. 增加新的元素類型會(huì)非常困難,每次新增元素類型,則訪問者類必須增加對(duì)應(yīng)元素類型的操作
  2. 違反了依賴倒置原則,訪問者依賴的是具體元素類型,而不是抽象
  3. 變更元素的屬性可能會(huì)導(dǎo)致對(duì)應(yīng)的訪問者類也需要修改
http://www.risenshineclean.com/news/55589.html

相關(guān)文章:

  • 網(wǎng)站開發(fā)需要哪些人員產(chǎn)品推廣軟件有哪些
  • 外國(guó)人可以在中國(guó)做網(wǎng)站嗎百度線上推廣
  • 北京市住房和城鄉(xiāng)建設(shè)委員會(huì)網(wǎng)站6優(yōu)化seo深圳
  • wordpress 判斷管理員seo數(shù)據(jù)分析哪些方面
  • 像優(yōu)酷這樣的網(wǎng)站需要怎么做百度官網(wǎng)入口
  • wordpress禁用php報(bào)錯(cuò)湖南seo推廣系統(tǒng)
  • 國(guó)外紅色企業(yè)網(wǎng)站公眾號(hào)推廣方案
  • 做網(wǎng)站優(yōu)化有什么方法短視頻營(yíng)銷優(yōu)勢(shì)
  • 網(wǎng)頁設(shè)計(jì)與網(wǎng)站建設(shè)...手機(jī)版谷歌瀏覽器入口
  • 邵陽屬于哪個(gè)省哪個(gè)市網(wǎng)站排名優(yōu)化的技巧
  • 怎么做網(wǎng)站熱線電話外鏈吧
  • 園林專業(yè)設(shè)計(jì)學(xué)習(xí)網(wǎng)站一個(gè)企業(yè)該如何進(jìn)行網(wǎng)絡(luò)營(yíng)銷
  • 沈陽市住房和城鄉(xiāng)建設(shè)部網(wǎng)站手機(jī)優(yōu)化大師官方免費(fèi)下載
  • 有教做點(diǎn)心的網(wǎng)站嗎網(wǎng)絡(luò)營(yíng)銷的定義
  • 網(wǎng)站建設(shè)公司響應(yīng)式網(wǎng)站模板溫州網(wǎng)站建設(shè)優(yōu)化
  • 微信網(wǎng)站開發(fā)語言百度游戲app下載
  • 帶icp備案的網(wǎng)站醫(yī)院營(yíng)銷策略的具體方法
  • 中國(guó)人民銀行網(wǎng)站查詢網(wǎng)址網(wǎng)站快速排名的方法
  • c語言做的網(wǎng)站有什么優(yōu)缺點(diǎn)國(guó)外最好的免費(fèi)建站
  • 青島做網(wǎng)站大公司有哪些重慶seo排
  • 購物網(wǎng)站建設(shè)需要什么資質(zhì)上海網(wǎng)絡(luò)推廣培訓(xùn)學(xué)校
  • 白云電子商務(wù)網(wǎng)站建設(shè)百度競(jìng)價(jià)托管費(fèi)用
  • 掃碼進(jìn)入網(wǎng)站如何做除了百度指數(shù)還有哪些指數(shù)
  • wordpress 視圖插件seo怎么優(yōu)化
  • 單機(jī)做游戲 迅雷下載網(wǎng)站微信運(yùn)營(yíng)方案
  • wordpress增加關(guān)鍵詞寧波seo在線優(yōu)化方案
  • 外貿(mào)做的社交網(wǎng)站營(yíng)銷網(wǎng)絡(luò)推廣方式有哪些
  • 鐵威馬 Nas 做網(wǎng)站整合營(yíng)銷傳播名詞解釋
  • 華強(qiáng)北網(wǎng)站建設(shè)華為手機(jī)網(wǎng)絡(luò)營(yíng)銷策劃方案
  • 做家教什么網(wǎng)站比較好sem培訓(xùn)班