访问者模式是一种行为设计模式。访问者模式被用在针对一组相同类型对象的操作。优点是,可以把针对此对象的操作逻辑转移到另外一个类上。
例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用。现在,计算逻辑即为计算这些不同类型商品的价格。或者说通过访问者模式我们把此逻辑转移到了另外一个类上面。让我们实现这个访问者模式的例子。
为了实现访问者模式,最先需要做的是创建能够被添加到购物车中代表不同类型商品(itemElement)的类。
ItemElement.java
1 |
package com.journaldev.design.visitor; |
3 |
public interface ItemElement
{ |
5 |
public int accept(ShoppingCartVisitor
visitor); |
注意,accept方法接受访问者作为参数。当然这儿还有其他的一些方法来指定详细的商品,但为了简化,此处没用过多的考虑细节,只关注访问者模式。
现在创建一些不同商品的实体类。
Book.java
01 |
package com.journaldev.design.visitor; |
03 |
public class Book implements ItemElement
{ |
06 |
private String
isbnNumber; |
08 |
public Book( int cost,
String isbn){ |
13 |
public int getPrice()
{ |
17 |
public String
getIsbnNumber() { |
22 |
public int accept(ShoppingCartVisitor
visitor) { |
23 |
return visitor.visit( this ); |
Fruit.java
01 |
package com.journaldev.design.visitor; |
03 |
public class Fruit implements ItemElement
{ |
05 |
private int pricePerKg; |
09 |
public Fruit( int priceKg, int wt,
String nm){ |
10 |
this .pricePerKg=priceKg; |
15 |
public int getPricePerKg()
{ |
19 |
public int getWeight()
{ |
23 |
public String
getName(){ |
28 |
public int accept(ShoppingCartVisitor
visitor) { |
29 |
return visitor.visit( this ); |
注意,accept()方法的实现是在实体类中,它调用访问者的visit()方法传递当前类对象作为自己的参数。
此处针对不同类型的商品所使用的visit()方法将会在访问者接口的实体类中被实现。
1 |
package com.journaldev.design.visitor; |
3 |
public interface ShoppingCartVisitor
{ |
6 |
int visit(Fruit
fruit); |
现在将实现访问者接口以及每种商品自己计算自己费用的逻辑。
01 |
package com.journaldev.design.visitor; |
03 |
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor
{ |
06 |
public int visit(Book
book) { |
09 |
if (book.getPrice()
> 50 ){ |
10 |
cost
= book.getPrice()- 5 ; |
11 |
} else cost
= book.getPrice(); |
12 |
System.out.println( "Book
ISBN::" +book.getIsbnNumber()
+ "
cost =" +cost); |
17 |
public int visit(Fruit
fruit) { |
18 |
int cost
= fruit.getPricePerKg()*fruit.getWeight(); |
19 |
System.out.println(fruit.getName()
+ "
cost = " +cost); |
现在看一看在程序中如何使用它。
01 |
package com.journaldev.design.visitor; |
03 |
public class ShoppingCartClient
{ |
05 |
public static void main(String[]
args) { |
06 |
ItemElement[]
items = new ItemElement[]{ new Book( 20 , "1234" ), new Book( 100 , "5678" ), |
07 |
new Fruit( 10 , 2 , "Banana" ), new Fruit( 5 , 5 , "Apple" )}; |
09 |
int total
= calculatePrice(items); |
10 |
System.out.println( "Total
Cost = " +total); |
13 |
private static int calculatePrice(ItemElement[]
items) { |
14 |
ShoppingCartVisitor
visitor = new ShoppingCartVisitorImpl(); |
16 |
for (ItemElement
item : items){ |
17 |
sum
= sum + item.accept(visitor); |
当运行上述程序是,我们得到如下输出。
1 |
Book
ISBN:: 1234 cost
= 20 |
2 |
Book
ISBN:: 5678 cost
= 95 |
请注意,此处的实现,好像accept()方法对于所有商品是相同的,但是他也可以不同。例如,如果商品为空它能进行逻辑检查并不再调用visit()方法。
访问者模式用例图
访问者模式的类图实现如下:

此模式的优点就是,如果操作的逻辑改变,我们只需要改变访问者的实现就够了,而不用去修改其他所有的商品类。
另一个好处是,添加新类别的商品到系统变得容易。只需要改变一下访问者接口以及其实现。已经存在的商品类别不会被干扰影响。
当然,访问者模式的缺点也需要知道,visit()方法的返回值的类型在设计系统式就需要明确。不然,就需要修改访问者的接口以及所有接口实现。另外如果访问者接口的实现太多,系统的扩展性就会下降。
转载:http://ifeve.com/visitor-design-pattern-in-java-example-tutorial/
案例源码下载:http://download.youkuaiyun.com/detail/ma20120607/8951193