1. 程式人生 > >設計模式解密(22)- 訪問者模式

設計模式解密(22)- 訪問者模式

ges action oid 使用 復合 con 9.png ava array

技術分享

前言:訪問者模式拆分

訪問者模式基礎篇 :http://www.cnblogs.com/JsonShare/p/7380772.html

訪問者模式擴展篇 - 分派的概念: http://www.cnblogs.com/JsonShare/p/7381705.html

1、簡介

定義:表示一個作用於其對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。

主要解決:穩定的數據結構和易變的操作耦合問題。就是把數據結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。

本質:預留通路,回調實現。它的實現主要就是通過預先定義好調用的通路,在被訪問的對象上定義accept方法,在訪問者的對象上定義visit方法;然後在調用真正發生的時候,通過兩次分發的技術,利用預先定義好的通路,回調到訪問者具體的實現上。

英文:Visitor

類型:行為型

2、類圖及組成

(引)類圖:

技術分享

組成:

  Visitor抽象訪問者接口:它定義了對每一個元素(Element)訪問的行為,它的參數就是可以訪問的元素,它的方法個數理論上來講與元素個數(Element的實現類個數)是一樣的,從這點不難看出,訪問者模式要求元素類的個數不能改變(不能改變的意思是說,如果元素類的個數經常改變,則說明不適合使用訪問者模式)。

  ConcreteVisitor具體訪問者角色:它需要給出對每一個元素類訪問時所產生的具體行為。

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

  ConcreteElement具體節點(元素)角色:它提供接受訪問方法的具體實現,而這個具體的實現,通常情況下是使用訪問者提供的訪問該元素類的方法。

  ObjectStructure結構對象角色:這個便是定義當中所提到的對象結構,對象結構是一個抽象表述,具體點可以理解為一個具有容器性質或者復合對象特性的類,它會含有一組元素(Element),並且可以叠代這些元素,供訪問者訪問。

代碼結構:

/**
 * 抽象訪問者角色:為每一個具體節點都準備了一個訪問操作。
 * 這裏由於有兩個節點,因此,對應就有兩個訪問操作。
 */
public interface Visitor {
    
/** * 對應於NodeA的訪問操作 */ public void visit(NodeA node); /** * 對應於NodeB的訪問操作 */ public void visit(NodeB node); } /** * 具體訪問者VisitorA類 */ public class VisitorA implements Visitor { /** * 對應於NodeA的訪問操作 */ @Override public void visit(NodeA node) { System.out.println(node.operationA()); } /** * 對應於NodeB的訪問操作 */ @Override public void visit(NodeB node) { System.out.println(node.operationB()); } } /** * 具體訪問者VisitorB類 */ public class VisitorB implements Visitor { /** * 對應於NodeA的訪問操作 */ @Override public void visit(NodeA node) { System.out.println(node.operationA()); } /** * 對應於NodeB的訪問操作 */ @Override public void visit(NodeB node) { System.out.println(node.operationB()); } } /** * 抽象節點類 */ public abstract class Node { /** * 接受操作 */ public abstract void accept(Visitor visitor); } /** * 具體節點類NodeA */ public class NodeA extends Node { /** * 接受操作 */ @Override public void accept(Visitor visitor) { visitor.visit(this); } /** * NodeA特有的方法 */ public String operationA() { return "NodeA"; } } /** * 具體節點類NodeB */ public class NodeB extends Node { /** * 接受方法 */ @Override public void accept(Visitor visitor) { visitor.visit(this); } /** * NodeB特有的方法 */ public String operationB() { return "NodeB"; } } /** * 結構對象角色類 * 這個結構對象角色持有一個聚集,並向外界提供add()方法作為對聚集的管理操作。通過調用這個方法,可以動態地增加一個新的節點。 */ public class ObjectStructure { private List<Node> nodes = new ArrayList<Node>(); /** * 執行方法操作 */ public void action(Visitor visitor) { for (Node node : nodes) { node.accept(visitor); } } /** * 添加一個新元素 */ public void add(Node node) { nodes.add(node); } } /** * 客戶端類 */ public class Client { public static void main(String[] args) { //創建一個結構對象 ObjectStructure os = new ObjectStructure(); //給結構增加一個節點 os.add(new NodeA()); //給結構增加一個節點 os.add(new NodeB()); //創建一個訪問者 Visitor visitor = new VisitorA(); os.action(visitor); } }

3、實例引入

場景:很多人都有養寵物的習慣,這裏就以此為例

訪問者角色:可以給寵物餵食的人

具體訪問者角色:主人、其他人

抽象元素角色:動物抽象類

具體元素角色:寵物狗、寵物貓

package com.designpattern.Visitor;

/**
 * 抽象訪問者接口  -- 人
 * @author Json<<[email protected]>>
 */
public abstract class Person {
    /**
     * 餵食狗
     */
    public abstract void feed(Cat cat);
    
    /**
     * 餵食貓
     */
    public abstract void feed(Dog dog);
}
package com.designpattern.Visitor;

/**
 * 具體訪問者角色 -- 主人
 * @author Json<<[email protected]>>
 */
public class Owner extends Person {

    @Override
    public void feed(Cat cat) {
        System.out.println("主人餵食貓");
    }

    @Override
    public void feed(Dog dog) {
        System.out.println("主人餵食狗");        
    }
}
package com.designpattern.Visitor;

/**
 * 具體訪問者角色 -- 其他人
 * @author Json<<[email protected]>>
 */
public class Someone extends Person {

    @Override
    public void feed(Cat cat) {
        System.out.println("其他人餵食貓");
    }

    @Override
    public void feed(Dog dog) {
        System.out.println("其他人餵食狗");        
    }
}
package com.designpattern.Visitor;

/**
 * 抽象節點(元素)角色 -- 寵物
 * @author Json<<[email protected]>>
 */
public abstract class Animal {
    //吃食操作
    public abstract void accept(Person person);
}
package com.designpattern.Visitor;

/**
 * 具體節點(元素)角色 -- 寵物狗
 * @author Json<<[email protected]>>
 */
public class Dog extends Animal {

    @Override
    public void accept(Person person) {
        person.feed(this);
        System.out.println("好好吃,汪汪汪!!!");
    }
}
package com.designpattern.Visitor;

/**
 * 具體節點(元素)角色 -- 寵物貓
 * @author Json<<[email protected]>>
 */
public class Cat extends Animal {

    @Override
    public void accept(Person person) {
        person.feed(this);
        System.out.println("好好吃,喵喵喵!!!");
    }
}
package com.designpattern.Visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * 結構對象角色類 -- 主人家
 * @author Json<<[email protected]>>
 */
public class Home {
    private List<Animal> nodeList = new ArrayList<>();

    public void action(Person person) {
        for (Animal node : nodeList) {
            node.accept(person);
        }
    }

    /**
     * 添加操作
     * @param animal
     */
    public void add(Animal animal) {
        nodeList.add(animal);
    }
}

測試:

package com.designpattern.Visitor;

/**
 * 客戶端測試
 * @author Json<<[email protected]>>
 */
public class Client {
    public static void main(String[] args) {
        Home owerHome = new Home();
        owerHome.add(new Dog());
        owerHome.add(new Cat());

        Owner owner = new Owner();
        owerHome.action(owner);
        
        Someone someone = new Someone();
        owerHome.action(someone);
    }
}

結果:

主人餵食狗
好好吃,汪汪汪!!!
主人餵食貓
好好吃,喵喵喵!!!
其他人餵食狗
好好吃,汪汪汪!!!
其他人餵食貓
好好吃,喵喵喵!!!

4、優缺點

優點:

  擴展性好:能夠在不修改對象結構中的元素的情況下,為對象結構中的元素添加新的功能。

  復用性好:可以通過訪問者來定義整個對象結構通用的功能,從而提高復用程度。

  分離無關行為:可以通過訪問者來分離無關的行為,把相關的行為封裝在一起,構成一個訪問者,這樣每一個訪問者的功能都比較單一。

缺點:

  對象結構變化很困難:不適用於對象結構中的類經常變化的情況,因為對象結構發生了改變,訪問者的接口和訪問者的實現都要發生相應的改變,代價太高。

  破壞封裝:訪問者模式通常需要對象結構開放內部數據給訪問者和ObjectStructrue,這破壞了對象的封裝性。

5、使用場景

  1、數據結構穩定,作用於數據結構的操作經常變化的時候。

  2、當一個數據結構中,一些元素類需要負責與其不相關的操作的時候,為了將這些操作分離出去,以減少這些元素類的職責時,可以使用訪問者模式。

  3、有時在對數據結構上的元素進行操作的時候,需要區分具體的類型,這時使用訪問者模式可以針對不同的類型,在訪問者類中定義不同的操作,從而去除掉類型判斷。

6、總結

  訪問者模式把數據結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用於數據結構相對穩定算法又易變化的系統。因為訪問者模式使得算法操作增加變得容易。若系統數據結構對象易於變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。

PS:源碼地址 https://github.com/JsonShare/DesignPattern/tree/master

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7380772.html

設計模式解密(22)- 訪問者模式