設計模式之-訪問者模式(Visitor Design Pattern)

訪問者模式行爲的設計模式之一。訪問者模式使用時,咱們必須是對一組相似種類對象統一操做。訪問者模式的幫助下,咱們能夠轉移這套邏輯到另外一個類進行操做

例如,考慮一個購物,咱們能夠添加不一樣類型的項目元素咱們點擊結賬按鈕,就計算要支付的總金額。如今,咱們能夠在項目計算邏輯,或者咱們能夠使用訪問者模式這個邏輯移動到另外一個類上使用這套訪問模式。讓咱們來實現這個訪問者模式的例子。

爲了實現訪問者模式,首先,咱們將建立不一樣類型的項目元素購物車中使用

java


ItemElement.java設計模式

package com.journaldev.design.visitor;
 
public interface ItemElement {
 
    public int accept(ShoppingCartVisitor visitor);
}

請注意,accept方法參數設置咱們能夠有一些其餘的方法,但爲了簡單起見,我不打算那麼多細節,只注重訪問者模式讓咱們建立一些具體的不一樣類型的項目

Book.javabash

package com.journaldev.design.visitor;
 
public class Book implements ItemElement {
 
    private int price;
    private String isbnNumber;
     
    public Book(int cost, String isbn){
        this.price=cost;
        this.isbnNumber=isbn;
    }
     
    public int getPrice() {
        return price;
    }
 
    public String getIsbnNumber() {
        return isbnNumber;
    }
 
    @Override
    public int accept(ShoppingCartVisitor visitor) {
        return visitor.visit(this);
    }
 
}

Fruit.javaapp

package com.journaldev.design.visitor;
 
public class Fruit implements ItemElement {
     
    private int pricePerKg;
    private int weight;
    private String name;
     
    public Fruit(int priceKg, int wt, String nm){
        this.pricePerKg=priceKg;
        this.weight=wt;
        this.name = nm;
    }
     
    public int getPricePerKg() {
        return pricePerKg;
    }
 
 
    public int getWeight() {
        return weight;
    }
 
    public String getName(){
        return this.name;
    }
     
    @Override
    public int accept(ShoppingCartVisitor visitor) {
        return visitor.visit(this);
    }
 
}

注意accept()方法具體的類的實現對其調用Visitor    visit()方法是,將自身做爲參數傳遞
咱們可使visit()方法不一樣類型的items,由實現Visitor接口具體的類去實現

ShoppingCartVisitor.javaide

package com.journaldev.design.visitor;
 
public interface ShoppingCartVisitor {
 
    int visit(Book book);
    int visit(Fruit fruit);
}

如今咱們實現 visitor接口,每一種item會有本身計算方法測試

ShoppingCartVisitorImpl.javaui

package com.journaldev.design.visitor;
 
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
 
    @Override
    public int visit(Book book) {
        int cost=0;
        //apply 5$ discount if book price is greater than 50
        if(book.getPrice() > 50){
            cost = book.getPrice()-5;
        }else cost = book.getPrice();
        System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);
        return cost;
    }
 
    @Override
    public int visit(Fruit fruit) {
        int cost = fruit.getPricePerKg()*fruit.getWeight();
        System.out.println(fruit.getName() + " cost = "+cost);
        return cost;
    }
 
}

測試程序:

ShoppingCartClient.javathis

package com.journaldev.design.visitor;
 
public class ShoppingCartClient {
 
    public static void main(String[] args) {
        ItemElement[] items = new ItemElement[]{new Book(20, "1234"),new Book(100, "5678"),
                new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
         
        int total = calculatePrice(items);
        System.out.println("Total Cost = "+total);
    }
 
    private static int calculatePrice(ItemElement[] items) {
        ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
        int sum=0;
        for(ItemElement item : items){
            sum = sum + item.accept(visitor);
        }
        return sum;
    }
 
}

輸出結果:

Book ISBN::1234 cost =20
Book ISBN::5678 cost =95
Banana cost = 20
Apple cost = 25
Total Cost = 160


請注意,若是執行accept()方法中的全部項目都是相同的,但也能夠是不一樣的,例如能夠有邏輯檢查項目是免費的,那麼請不要調用visit()方法的。
spa

Visitor Pattern Class Diagram:


總結:設計

這種模式的好處是,若是操做的邏輯改變了那麼咱們就須要作出改變在訪問者實現,而不是作在全部的項目類別
另外一個好處是,增長一個新的項目,對於系統很容易實現,只須要implements訪問者的接口和實現便可,對於現有的項目類別將不會受到影響
訪問者模式缺點:咱們必須知道visit()方法的返回值類型才能夠這樣設計,否則咱們將不得不改變界面全部的實現。另外一個缺點是,若是數量太多的visitor接口實現項目將很難擴展

相關文章
相關標籤/搜索