亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android編程設(shè)計(jì)模式之訪問(wèn)者模式詳解

 更新時(shí)間:2017年12月27日 10:29:10   作者:蹲街式等待  
這篇文章主要介紹了Android編程設(shè)計(jì)模式之訪問(wèn)者模式,詳細(xì)分析了訪問(wèn)者模式的概念、功能、原理、使用場(chǎng)景并結(jié)合實(shí)例形式給出了Android訪問(wèn)者模式的具體實(shí)現(xiàn)技巧與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了Android編程設(shè)計(jì)模式之訪問(wèn)者模式。分享給大家供大家參考,具體如下:

一、介紹

訪問(wèn)者模式是一種將數(shù)據(jù)操作與數(shù)據(jù)結(jié)構(gòu)分離的設(shè)計(jì)模式,它是《設(shè)計(jì)模式》中23種設(shè)計(jì)模式中最復(fù)雜的一個(gè),但它的使用頻率并不高,正如《設(shè)計(jì)模式》的作者GOF對(duì)訪問(wèn)者模式的描述:大多數(shù)情況下,你不需要使用訪問(wèn)者模式,但是當(dāng)你一旦需要使用它時(shí),那你就是真的需要它了。

訪問(wèn)者模式的基本想法是,軟件系統(tǒng)中擁有一個(gè)由許多對(duì)象構(gòu)成的、比較穩(wěn)定的對(duì)象結(jié)構(gòu),這些對(duì)象的類都擁有一個(gè)accept方法用來(lái)接受訪問(wèn)者對(duì)象的訪問(wèn)。訪問(wèn)者是一個(gè)接口,它擁有一個(gè)visit方法,這個(gè)方法對(duì)訪問(wèn)到的對(duì)象結(jié)構(gòu)中不同類型的元素作出不同的處理。在對(duì)象結(jié)構(gòu)的一次訪問(wèn)過(guò)程中,我們遍歷整個(gè)對(duì)象結(jié)構(gòu),對(duì)每一個(gè)元素都實(shí)施accept方法,在每一個(gè)元素的accept方法中會(huì)調(diào)用訪問(wèn)者的visit方法,從而使訪問(wèn)者得以處理對(duì)象結(jié)構(gòu)的每一個(gè)元素,我們可以針對(duì)對(duì)象結(jié)構(gòu)設(shè)計(jì)不同的訪問(wèn)者類來(lái)完成不同的操作,達(dá)到區(qū)別對(duì)待的效果。

二、定義

封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。

三、使用場(chǎng)景

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

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

四、訪問(wèn)者模式的UML類圖

UML類圖:

角色介紹:

Visitor:接口或抽象類,定義了對(duì)每一個(gè)元素的訪問(wèn)行為,參數(shù)就是可訪問(wèn)的元素,方法個(gè)數(shù)理論上是個(gè)元素個(gè)數(shù)一樣的。因此,訪問(wèn)者模式要求被訪問(wèn)的對(duì)象結(jié)構(gòu)要穩(wěn)定,如果經(jīng)常增刪元素,必然會(huì)導(dǎo)致頻繁修改Visitor接口,就不適合用訪問(wèn)者模式了。

ConcreteVisitor:具體的訪問(wèn)者,定義具體的對(duì)每一個(gè)元素的具體訪問(wèn)行為。

Element:抽象的元素接口或抽象類,定義了一個(gè)接待訪問(wèn)者的方法,讓每個(gè)元素都可以被訪問(wèn)者訪問(wèn)。

ElementA,ElementB:具體的元素類,提供接收訪問(wèn)方法的具體實(shí)現(xiàn)。這個(gè)具體實(shí)現(xiàn)通常是調(diào)用訪問(wèn)者提供的訪問(wèn)該元素的方法。

ObjectStructure:定義對(duì)象結(jié)構(gòu),里面維護(hù)了一個(gè)元素的集合,并且迭代這些元素供訪問(wèn)者訪問(wèn)。

五、簡(jiǎn)單示例

情景:年終了,公司會(huì)給員工進(jìn)行業(yè)績(jī)考核。但是,不同領(lǐng)域的管理人員對(duì)于員工的評(píng)定標(biāo)準(zhǔn)不一樣?,F(xiàn)在員工有工程師和經(jīng)理,評(píng)定者有CEO和CTO,我們假定CTO只關(guān)注工程師的代碼量、經(jīng)理的新產(chǎn)品數(shù)量,而CEO關(guān)注的是工程師的KPI和經(jīng)理的KPI以及新產(chǎn)品數(shù)量。

員工基類:

/**
 * 員工基類(Element) 
 */
public abstract class Staff {
  //員工姓名
  public String name;
  //員工KPI
  public int kpi;
  public Staff(String name) {
    super();
    this.name = name;
    this.kpi = new Random().nextInt(10);
  }
  //接受Visitor的訪問(wèn)
  public abstract void accept(Visitor visitor);
}

工程師:

/**
 * 工程師 
 */
public class Engineer extends Staff{
  private int codeLines;//代碼數(shù)量
  public Engineer(String name) {
    super(name);
    codeLines = new Random().nextInt(10 * 10000);
  }
  @Override
  public void accept(Visitor visitor) {
    visitor.visit(this);
  }
  //工程師這一年寫的代碼數(shù)量
  public int getCodeLines(){
    return codeLines;
  }
}

經(jīng)理:

/**
 * 經(jīng)理
 */
public class Manager extends Staff{
  private int products;//產(chǎn)品數(shù)量
  public Manager(String name) {
    super(name);
    products = new Random().nextInt(10);
  }
  @Override
  public void accept(Visitor visitor) {
    visitor.visit(this);
  }
  //一年內(nèi)做的產(chǎn)品數(shù)量
  public int getProducts(){
    return products;
  }
}

Visitor類:

public interface Visitor {
  /**
   * 訪問(wèn)工程師類型
   */
  public void visit(Engineer engineer);
  /**
   * 訪問(wèn)經(jīng)理類型
   */
  public void visit(Manager manager);
}

CEO訪問(wèn)者:

public class CEOVisitor implements Visitor {
  @Override
  public void visit(Engineer engineer) {
    System.out.println("工程師:" + engineer.name + ", KPI:" + engineer.kpi);
  }
  @Override
  public void visit(Manager manager) {
    System.out.println("經(jīng)理:" + manager.name + ", KPI:" + manager.kpi
        + ", 新產(chǎn)品數(shù)量 :" + manager.getProducts());
  }
}

CTO訪問(wèn)者:

public class CTOVisitor implements Visitor {
  @Override
  public void visit(Engineer engineer) {
    System.out.println("工程師:" + engineer.name + ", 代碼數(shù)量:" + engineer.getCodeLines());
  }
  @Override
  public void visit(Manager manager) {
    System.out.println("經(jīng)理:" + manager.name +", 產(chǎn)品數(shù)量 :" + manager.getProducts());
  }
}

員工報(bào)表:

//員工業(yè)務(wù)報(bào)表類(ObjectStructure)
public class BusinessReport {
  List<Staff> mStaffs = new LinkedList<Staff>();
  public BusinessReport() {
    mStaffs.add(new Manager("王經(jīng)理"));
    mStaffs.add(new Engineer("工程師-A"));
    mStaffs.add(new Engineer("工程師-B"));
    mStaffs.add(new Manager("李經(jīng)理"));
    mStaffs.add(new Engineer("工程師-C"));
  }
  /**
   * 為訪問(wèn)者展示報(bào)表 
   * @param visitor 如CEO、CTO
   */
  public void showReport(Visitor visitor){
    for(Staff staff : mStaffs){
      staff.accept(visitor);
    }
  }
}

Client訪問(wèn):

public class Client {
  public static void main(String[] args) {
    //構(gòu)建報(bào)表
    BusinessReport report = new BusinessReport();
    System.out.println("===== 給CEO看報(bào)表 =====");
    //設(shè)置訪問(wèn)者CEO
    report.showReport(new CEOVisitor());
    System.out.println("===== 給CTO看報(bào)表 =====");
    //設(shè)置訪問(wèn)者CTO
    report.showReport(new CTOVisitor());
  }
}

結(jié)果:

===== 給CEO看報(bào)表 =====
經(jīng)理:王經(jīng)理, KPI:2, 新產(chǎn)品數(shù)量 :5
工程師:工程師-A, KPI:5
工程師:工程師-B, KPI:7
經(jīng)理:李經(jīng)理, KPI:9, 新產(chǎn)品數(shù)量 :8
工程師:工程師-C, KPI:1
===== 給CTO看報(bào)表 =====
經(jīng)理:王經(jīng)理, 產(chǎn)品數(shù)量 :5
工程師:工程師-A, 代碼數(shù)量:26238
工程師:工程師-B, 代碼數(shù)量:8282
經(jīng)理:李經(jīng)理, 產(chǎn)品數(shù)量 :8
工程師:工程師-C, 代碼數(shù)量:47927

從上面代碼中可以看出,如果要增加一個(gè)訪問(wèn)者,你新創(chuàng)建一個(gè)實(shí)現(xiàn)了Visitor接口的類,然后實(shí)現(xiàn)兩個(gè)visit方法來(lái)對(duì)不同的元素進(jìn)行不同的操作,從而達(dá)到數(shù)據(jù)對(duì)象與數(shù)據(jù)操作相分離的效果。如果不使用訪問(wèn)者模式,而又想對(duì)不同元素進(jìn)行不同的操作,那么必定會(huì)使用if-else和類型轉(zhuǎn)換,這使得代碼難以升級(jí)維護(hù)。

六、Android中的訪問(wèn)者模式

安卓中的著名開(kāi)源庫(kù)ButterKnife、Dagger、Retrofit都是基于APT(Annotation Processing Tools)實(shí)現(xiàn)。而編譯注解核心依賴APT。當(dāng)我們通過(guò)APT處理注解時(shí),最終會(huì)將獲取到的元素轉(zhuǎn)換為相應(yīng)的Element元素,以便獲取到它們對(duì)應(yīng)信息。那么元素基類的源碼如下:(路徑:javax.lang.model.element.Element)

public interface Element extends javax.lang.model.AnnotatedConstruct {
  /**
   * Returns the {@code kind} of this element.
   *
   * @return the kind of this element
   */
  ElementKind getKind();//獲取元素類型
  //代碼省略
  /**
   * Applies a visitor to this element.
   *
   * @param <R> the return type of the visitor's methods
   * @param <P> the type of the additional parameter to the visitor's methods
   * @param v  the visitor operating on this element
   * @param p  additional parameter to the visitor
   * @return a visitor-specified result
   */
  <R, P> R accept(ElementVisitor<R, P> v, P p);//接受訪問(wèn)者的訪問(wèn)
}

ElementVisitor就是訪問(wèn)者類型,ElementVisitor源碼如下:

public interface ElementVisitor<R, P> {
  /**
   * Visits an element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visit(Element e, P p);
  /**
   * A convenience method equivalent to {@code v.visit(e, null)}.
   * @param e the element to visit
   * @return a visitor-specified result
   */
  R visit(Element e);
  /**
   * Visits a package element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visitPackage(PackageElement e, P p);
  /**
   * Visits a type element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visitType(TypeElement e, P p);
  /**
   * Visits a variable element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visitVariable(VariableElement e, P p);
  /**
   * Visits an executable element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visitExecutable(ExecutableElement e, P p);
  /**
   * Visits a type parameter element.
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   */
  R visitTypeParameter(TypeParameterElement e, P p);
  /**
   * Visits an unknown kind of element.
   * This can occur if the language evolves and new kinds
   * of elements are added to the {@code Element} hierarchy.
   *
   * @param e the element to visit
   * @param p a visitor-specified parameter
   * @return a visitor-specified result
   * @throws UnknownElementException
   * a visitor implementation may optionally throw this exception
   */
  R visitUnknown(Element e, P p);
}

在ElementVisitor中定義了多種visit接口,每個(gè)接口處理一種元素類型,那么這就是典型的訪問(wèn)者模式。

七、總結(jié)

正如本節(jié)開(kāi)頭引用GOF的話所說(shuō):大多數(shù)情況下,你不需要使用訪問(wèn)者模式,但是,當(dāng)你一旦需要使用它時(shí),那你就是真的需要它了。在現(xiàn)實(shí)情況下,我們要根據(jù)具體的情況來(lái)評(píng)估是否適合使用訪問(wèn)者模式,例如,我們的對(duì)象結(jié)構(gòu)是否足夠穩(wěn)定,使用訪問(wèn)者模式是否能夠優(yōu)化我們的代碼,而不是使我們的代碼變得更復(fù)雜。在使用一個(gè)模式之前,我們應(yīng)該明確它的使用場(chǎng)景、它能解決什么問(wèn)題等,以此來(lái)避免濫用設(shè)計(jì)模式的現(xiàn)象。

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

各角色職責(zé)分離,符合單一職責(zé)原則。

具有優(yōu)秀的擴(kuò)展性。

使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦,使得操作集合可以獨(dú)立變化。

靈活性。

缺點(diǎn):

具體元素對(duì)訪問(wèn)者公布細(xì)節(jié),違反了迪米特原則。

具體元素變更時(shí)導(dǎo)致修改成本大。

違反了依賴倒置原則,為了達(dá)到“區(qū)別對(duì)待”而依賴了具體類,沒(méi)有依賴抽象。

更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android開(kāi)發(fā)入門與進(jìn)階教程》、《Android調(diào)試技巧與常見(jiàn)問(wèn)題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)

希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Android編程中全局變量問(wèn)題分析

    Android編程中全局變量問(wèn)題分析

    這篇文章主要介紹了Android編程中全局變量,較為詳細(xì)的分析了全局變量的功能并結(jié)合案例形式講述了全局變量所引起的問(wèn)題及相應(yīng)的解決技巧,需要的朋友可以參考下
    2016-11-11
  • Android設(shè)置拍照或者上傳本地圖片的示例

    Android設(shè)置拍照或者上傳本地圖片的示例

    本篇文章主要介紹了Android設(shè)置拍照或者上傳本地圖片示例,可以拍照或者上傳本地文件,有需要的可以了解一下。
    2016-11-11
  • Android中使用Gradle來(lái)構(gòu)建App項(xiàng)目的入門指南

    Android中使用Gradle來(lái)構(gòu)建App項(xiàng)目的入門指南

    Gradle是Java世界中一個(gè)高人氣自動(dòng)化構(gòu)建工具,在安卓開(kāi)發(fā)領(lǐng)域同樣備受追捧,這里為大家?guī)?lái)Android中使用Gradle來(lái)構(gòu)建App項(xiàng)目的入門指南,來(lái)看看Gradle的作用與基本結(jié)構(gòu).
    2016-06-06
  • Android版多線程下載 仿下載助手(最新)

    Android版多線程下載 仿下載助手(最新)

    我們都知道,下載助手,比如360,百度的 手機(jī)助手,下載APP的時(shí)候 ,都可以同時(shí)下載多個(gè),所以下載肯定是多線程的,所以我們就需要一個(gè)線程工具類來(lái)管理我們的線程,這個(gè)工具類的核心,就是線程池。接下來(lái)給大家介紹Android版多線程下載 仿下載助手(最新)
    2015-08-08
  • Android相冊(cè)效果(使用C#和Java分別實(shí)現(xiàn))

    Android相冊(cè)效果(使用C#和Java分別實(shí)現(xiàn))

    這篇文章主要介紹了Android相冊(cè)效果(使用C#和Java分別實(shí)現(xiàn)),原來(lái)C#也可以開(kāi)發(fā)APP,小編第一次見(jiàn)了~感覺(jué)不錯(cuò),因?yàn)樾【帟簳r(shí)不喜歡Java,所以,需要的朋友可以參考下
    2015-06-06
  • flutter的環(huán)境安裝配置問(wèn)題及解決方法

    flutter的環(huán)境安裝配置問(wèn)題及解決方法

    Flutter是Google推出的基于Dart語(yǔ)言開(kāi)發(fā)的跨平臺(tái)開(kāi)源UI框架,旨在統(tǒng)一紛紛擾擾的跨平臺(tái)開(kāi)發(fā)框架,在UI層面上多端共用一套Dart代碼來(lái)實(shí)現(xiàn)多平臺(tái)適配開(kāi)發(fā),這篇文章主要介紹了flutter的環(huán)境安裝配置問(wèn)題,需要的朋友可以參考下
    2020-06-06
  • Android 同時(shí)setTag兩次保存多種值的示例代碼

    Android 同時(shí)setTag兩次保存多種值的示例代碼

    這篇文章主要介紹了Android 同時(shí)setTag兩次保存多種值的示例代碼,需要的朋友可以參考下
    2017-02-02
  • NestScrollView嵌套R(shí)ecyclerView實(shí)現(xiàn)淘寶首頁(yè)滑動(dòng)效果

    NestScrollView嵌套R(shí)ecyclerView實(shí)現(xiàn)淘寶首頁(yè)滑動(dòng)效果

    這篇文章主要介紹了NestScrollView嵌套R(shí)ecyclerView實(shí)現(xiàn)淘寶首頁(yè)滑動(dòng)效果,主要實(shí)現(xiàn)淘寶首頁(yè)嵌套滑動(dòng),中間tab吸頂效果,以及介紹NestScrollView嵌套R(shí)ecyclerView處理滑動(dòng)沖突的方法,需要的朋友可以參考下
    2021-12-12
  • 第1個(gè)Android應(yīng)用程序 Android制作簡(jiǎn)單單頁(yè)導(dǎo)航

    第1個(gè)Android應(yīng)用程序 Android制作簡(jiǎn)單單頁(yè)導(dǎo)航

    這篇文章主要為大家詳細(xì)介紹了第1個(gè)Android應(yīng)用程序PhonewordApp:Android制作簡(jiǎn)單單頁(yè)導(dǎo)航,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android中ViewFlipper的使用及設(shè)置動(dòng)畫效果實(shí)例詳解

    Android中ViewFlipper的使用及設(shè)置動(dòng)畫效果實(shí)例詳解

    這篇文章主要介紹了Android中ViewFlipper的使用及設(shè)置動(dòng)畫效果的方法,以實(shí)例形式較為詳細(xì)的分析了ViewFlipper的功能、原理及設(shè)置與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10

最新評(píng)論