最近刚好在看于广老师的《Java开发技术:在架构中体验设计模式和算法之美》这本书。于是,也就是边看边学习。
Java设计模式分为;创建者型模式、结构型模式、行为型模式。今天学习下行为型模式里面的访问者模式。
访问者模式定义:表示一个作用于某对象结构中的各元素的操作,它可以在不改变各元素的类的前提下定义作用于这些元素的新操作(通俗来说也就是一个操作,什么操作呢?作用于对象类的元素的操作)
构成访问者模式的角色有以下几个:
访问者角色:对结构对象中的具体元素角色声明一个访问操作接口。
具体访问者角色:实现访问操作接口的操作。
元素角色:定义一个accept操作,传入一个访问者参数。
具体元素角色:实现由元素角色提供的accept操作。
对象结构角色:它可以枚举出所有的元素。
下面举一个项目中常见的例子(参考http://ifeve.com/visitor-design-pattern-in-java-example-tutorial/)。购物车功能,用户可以购买不同类型的物品,提交到购物车里面,最后提交所有订单计算总价。其中,计算订单的总价就是很好的运用访问者模式,下面我们可以画出这个功能通过访问者模式实现的类图结构如下图1-1:
好了,结构图画完了,然后就是实现代码了。
IElement.java类代码如下:
public interface IElement {
int accept(Visitor visitor);
}
Fruits.java类代码:
public class Fruits implements IElement{
private int pricePerKg;
private int weight;
private String name;
public Fruits(int pricePerKg, int weight, String name) {
super();
this.pricePerKg = pricePerKg;
this.weight = weight;
this.name = name;
}
public int getPricePerKg() {
return pricePerKg;
}
public int getWeight() {
return weight;
}
public String getName() {
return name;
}
@Override
public int accept(Visitor visitor) {
// TODO Auto-generated method stub
return visitor.visit(this);
}
}
Book.java类代码:
public class Book implements IElement{
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(Visitor visitor) {
// TODO Auto-generated method stub
return visitor.visit(this);
}
}
Visitor接口实现:
public interface Visitor {
int visit(Fruits fruits);
int visit(Book books);
}
ConcreateVisitener1.java类实现:
“`
public class ConcreateVisitener1 implements Visitor{
@Override
public int visit(Fruits fruits) {
int cost = fruits.getPricePerKg()*fruits.getWeight();
System.out.println(fruits.getName() + " cost = "+cost);
return cost;
}
@Override
public int visit(Book books) {
int cost=0;
//apply 5$ discount if book price is greater than 50
if(books.getPrice() > 50){
cost = books.getPrice()-5;
}else cost = books.getPrice();
System.out.println("Book ISBN::"+books.getIsbnNumber() + " cost ="+cost);
return cost;
}
}
Client.java类实现:
public class Client {
public static void main(String[] args) {
IElement[] items = new IElement[] { new Book(20, “1234”),
new Book(100, “5678”), new Fruits(10, 2, “Banana”),
new Fruits(5, 5, “Apple”) };
int total = calculatePrice(items);
System.out.println(“Total Cost = ” + total);
}
private static int calculatePrice(IElement[] items) {
ConcreateVisitener1 visitor = new ConcreateVisitener1();
int sum = 0;
for (IElement item : items) {
sum = sum + item.accept(visitor);
}
return sum;
}
}
好了,run下就行了。
总结:
访问者模式的优点:
1. 访问者模式增加新的操作变得容易,增加一个新的操作,也就是增加一个新的访问类。因此,就变得很容易了。
2. 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个节点类中,比如这里我们把所有计算的都放在具体访问者角色里面。
3. 访问者模式可以跨过几个类的等级结构访问属于不同等级结构的成员类。比如迭代器只能访问属于同一个类型等级结构的成员对象,而不能访问不同等级结构的对象。
4. 积累状态,每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程执行操作的状态积累在自己的内部,而不是分到很多的节点对象中。
访问者模式的缺点
1. 增加新的节点类变得很困难,每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问类中增加相应的具体操作。
2. 破坏封装,访问者模式要求访问者对象访问并调用每一个节点对象的操作,这样就暴露一些自己的操作和内部状态。从而破坏了封装性。
好了,差不多就是这样了。后面再慢慢学习。