Java中的访问者设计模式

访问者设计模式是行为设计模式之一。

访问者设计模式

当我们需要对一组相似类型的对象执行操作时,使用访问者模式。借助访问者模式,我们可以将操作逻辑从对象移动到另一个类中。例如,想象一个购物车,我们可以添加不同类型的物品(元素)。当我们点击结算按钮时,它会计算要支付的总金额。现在我们可以将计算逻辑放在物品类中,也可以使用访问者模式将此逻辑移到另一个类中。让我们在访问者模式的示例中实施这个功能。

访问者设计模式的Java示例

为了实现访问者模式,首先我们将创建不同类型的物品(元素),以便在购物车中使用。ItemElement.java

package com.Olivia.design.visitor;

public interface ItemElement {

	public int accept(ShoppingCartVisitor visitor);
}

请注意accept方法需要一个Visitor参数。我们也可以有一些其他方法,专门用于项目,但为了简单起见,我不打算过多详细介绍,只专注于访问者模式。让我们为不同类型的项目创建一些具体的类。例如Book.java。

package com.Olivia.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.java -> 水果.java

package com.Olivia.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()方法并将自身作为参数传递。在Visitor接口中,我们为不同类型的物品定义了visit()方法,这些方法将由具体访问者类来实现。ShoppingCartVisitor.java

package com.Olivia.design.visitor;

public interface ShoppingCartVisitor {

	int visit(Book book);
	int visit(Fruit fruit);
}

现在我们将实现访问者接口,并为每个物品编写自己的逻辑来计算成本。在ShoppingCartVisitorImpl.java文件中。

package com.Olivia.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.java 来实现。

package com.Olivia.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()方法。

访问者设计模式类图

我们的访客设计模式实现的类图为:

访问者模式的好处

这种模式的好处是,如果操作的逻辑发生变化,我们只需要在访问者实现中进行修改,而不需要在所有的项目类中进行修改。另一个好处是,向系统中添加新的项目很容易,只需要在访问者接口和实现中进行修改,现有的项目类不会受到影响。

访问者模式的局限性

访问者模式的缺点是我们在设计时需要知道visit()方法的返回类型,否则我们将不得不更改接口及其所有实现。另一个缺点是如果访问者接口有太多实现,扩展将变得困难。关于访问者设计模式的内容就这些,如果我遗漏了什么,请告诉我。如果你喜欢的话,请与其他人分享。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds