访问者模式是行为的设计模式之一。访问者模式的使用时,咱们必须是对一组相似种类对象统一操做。在访问者模式的帮助下,咱们能够转移这套逻辑到另外一个类进行操做。
例如,考虑一个购物车,咱们能够添加不一样类型的项目(元素),当咱们点击结账按钮,就计算要支付的总金额。如今,咱们能够在项目类的计算逻辑,或者咱们能够使用访问者模式这个逻辑移动到另外一个类上使用这套访问模式。让咱们来实现这个访问者模式的例子。
为了实现访问者模式,首先,咱们将建立不一样类型的项目(元素)在购物车中使用的。
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接口实现,项目将很难扩展。