网站根域名是什么,做算命类网站违法吗?,竞价账户托管公司,想建书画网站怎么做的1 访问者模式介绍
访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式。
2 访问者模式原理 3 访问者模式实现
我们以超市购物为例,假设超市中的三类商品: 水果,糖…1 访问者模式介绍
访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式。
2 访问者模式原理 3 访问者模式实现
我们以超市购物为例,假设超市中的三类商品: 水果,糖果,酒水进行售卖. 我们可以忽略每种商品的计价方法,因为最终结账时由收银员统一集中处理,在商品类中添加计价方法是不合理的设计.我们先来定义糖果类和酒类、水果类.
/*** 抽象商品父类**/
public abstract class Product {private String name; //商品名private LocalDate produceDate; //生产日期private double price; //商品价格public Product(String name, LocalDate produceDate, double price) {this.name name;this.produceDate produceDate;this.price price;}public String getName() {return name;}public void setName(String name) {this.name name;}public LocalDate getProduceDate() {return produceDate;}public void setProduceDate(LocalDate produceDate) {this.produceDate produceDate;}public double getPrice() {return price;}public void setPrice(double price) {this.price price;}
}/*** 糖果类**/
public class Candy extends Product implements Acceptable{public Candy(String name, LocalDate produceDate, double price) {super(name, produceDate, price);}Overridepublic void accept(Visitor visitor) {//在accept方法中调用访问者, 并将自己 this 传递回去.visitor.visit(this);}
}/*** 酒水类**/
public class Wine extends Product implements Acceptable{public Wine(String name, LocalDate produceDate, double price) {super(name, produceDate, price);}Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}/*** 水果类**/
public class Fruit extends Product implements Acceptable{private double weight; //重量public Fruit(String name, LocalDate produceDate, double price, double weight) {super(name, produceDate, price);this.weight weight;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight weight;}Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}访问者接口
收银员就类似于访问者,访问用户选择的商品,我们假设根据生产日期进行打折,过期商品不能够出售. 注意这种计价策略不适用于酒类,作为收银员要对不同商品应用不同的计价方法。
/*** 访问者接口 - 根据入参的不同调用对应的重载方法**/
public interface Visitor {public void visit(Candy candy); //糖果重载方法public void visit(Wine wine); //酒类重载方法public void visit(Fruit fruit); //水果重载方法
}具体访问者
创建计价业务类,对三类商品进行折扣计价,折扣计价访问者的三个重载方法分别实现了3类商品的计价方法,体现了visit() 方法的多态性.
/*** 折扣计价访问者类**/
public class DiscountVisitor implements Visitor {private LocalDate billDate;public DiscountVisitor(LocalDate billDate) {this.billDate billDate;System.out.println(结算日期: billDate);}Overridepublic void visit(Candy candy) {System.out.println(糖果: candy.getName());//糖果大于180天,禁止售卖,否则糖果一律九折long days billDate.toEpochDay() - candy.getProduceDate().toEpochDay();if(days 180){System.out.println(超过半年的糖果,请勿食用!);}else{double realPrice candy.getPrice() * 0.9;System.out.println(糖果打折后的价格为: NumberFormat.getCurrencyInstance().format(realPrice));}}Overridepublic void visit(Wine wine) {System.out.println(酒类: wine.getName() ,无折扣价格!);System.out.println(原价售卖: NumberFormat.getCurrencyInstance().format(wine.getPrice()));}Overridepublic void visit(Fruit fruit) {System.out.println(水果: fruit.getName());long days billDate.toEpochDay() - fruit.getProduceDate().toEpochDay();double rate 0;if(days 7){System.out.println(超过七天的水果,请勿食用!);}else if(days 3){rate 0.5;}else{rate 1;}double realPrice fruit.getPrice() * fruit.getWeight() * rate;System.out.println(水果价格为: NumberFormat.getCurrencyInstance().format(realPrice));}
}public class Client {public static void main(String[] args) {// Candy candy new Candy(德芙巧克力, LocalDate.of(2022, 1, 1), 10.0);
//
// Visitor visitor new DiscountVisitor(LocalDate.of(2022,10,5));
// visitor.visit(candy);//将3件商品加入购物车
// ListProduct products Arrays.asList(
// new Candy(金丝猴奶糖,LocalDate.of(2022,10,1),10),
// new Wine(郎酒,LocalDate.of(2022,10,1),1000),
// new Fruit(草莓,LocalDate.of(2022,10,8),50,1)
// );// Visitor visitor new DiscountVisitor(LocalDate.of(2022,10,5));
// for (Product product : products) {
// //visitor.visit();
// }//模拟添加多个商品ListAcceptable list Arrays.asList(new Candy(金丝猴奶糖,LocalDate.of(2022,10,1),10),new Wine(郎酒,LocalDate.of(2022,10,1),1000),new Fruit(草莓,LocalDate.of(2022,10,8),50,1));Visitor visitor new DiscountVisitor(LocalDate.of(2022,10,11));for (Acceptable product : list) {product.accept(visitor);}}
}上面的代码虽然可以完成当前的需求,但是设想一下这样一个场景: 由于访问者的重载方法只能对当个的具体商品进行计价,如果顾客选择了多件商品来结账时,就可能会引起重载方法的派发问题(到底该由谁来计算的问题).
首先我们定义一个接待访问者的类 Acceptable,其中定义了一个accept(Visitor visitor)方法, 只要是visitor的子类都可以接收.
/*** 接待者这接口 (抽象元素角色)**/
public interface Acceptable {//接收所有的Visitor访问者的子类public void accept(Visitor visitor);
}/**
* 糖果类
* author spikeCong
* date 2022/10/18
**/
public class Candy extends Product implements Acceptable{public Candy(String name, LocalDate producedDate,double price) {super(name, producedDate, price);}//测试Overridepublic void accept(Visitor visitor) {//accept实现方法中调用访问者并将自己 this 传回。this是一个明确的身份,不存在任何泛型visitor.visit(this);}
}代码编写到此出,就可以应对计价方式或者业务逻辑的变化了,访问者模式成功地将数据资源需实现接待者接口与数据算法 需实现访问者接口分离开来。重载方法的使用让多样化的算法自成体系多态化的访问者接口保证了系 统算法的可扩展性数据则保持相对固定最终形成⼀个算法类对应⼀套数据。
4 访问者模式总结