訪問者模式是行爲的設計模式之一。訪問者模式的使用時,咱們必須是對一組相似種類對象統一操做。在訪問者模式的幫助下,咱們能夠轉移這套邏輯到另外一個類進行操做。
例如,考慮一個購物車,咱們能夠添加不一樣類型的項目(元素),當咱們點擊結賬按鈕,就計算要支付的總金額。如今,咱們能夠在項目類的計算邏輯,或者咱們能夠使用訪問者模式這個邏輯移動到另外一個類上使用這套訪問模式。讓咱們來實現這個訪問者模式的例子。
爲了實現訪問者模式,首先,咱們將建立不一樣類型的項目(元素)在購物車中使用的。
java
ItemElement.java設計模式
package com.journaldev.design.visitor; public interface ItemElement { public int accept(ShoppingCartVisitor visitor); }
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); } }
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
總結:設計
這種模式的好處是,若是操做的邏輯改變了,那麼咱們就須要作出改變只在訪問者實現,而不是作在全部的項目類別。
另外一個好處是,增長一個新的項目,對於系統很容易實現,只須要implements訪問者的接口和實現便可,對於現有的項目類別將不會受到影響。
訪問者模式的缺點:咱們必須知道visit()方法的返回值類型才能夠這樣設計,否則咱們將不得不改變界面和全部的實現。另外一個缺點是,若是有數量太多的visitor接口實現,項目將很難擴展。