访问者模式,是指在一个相对固定不变的系统,因需要接受不同的外部对象对其的调用,将每个不同外部对象的不同实现交给外部对象自己。而系统本身需要定义好接口交给外部对象去实现
/**
* 商品
* */
public abstract class Product {
//视频名称
String name;
//价格
int price;
public abstract void buy();
}
/**
*视频
* */
public class Video extends Product{
public Video(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(){
System.out.println(name+"以"+price+"成交");
}
}
/**
* 小说
* */
public class Story extends Product{
public Story(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(){
System.out.println(name+"以"+price+"成交");
}
}
/**
* 音乐
* */
public class Music extends Product{
public Music(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(){
System.out.println(name+"以"+price+"成交");
}
}
/**
* 商店
* */
public class Shop {
//商品容器
private ArrayList<Product> contain;
public Shop(ArrayList<Product> contain){
this.contain = contain;
}
}
如上所示,上述系统是一个商店,里面有视频,音乐,小说三种不同的商品,目前的出售的方式均是以原价出售
现在推出新的营销策略: 京东过来的客户,视频9折,音乐8折,小说7折
淘宝过来的客户,视频8折,音乐7折,小说6折
拼多多过来的客户,视频7折,音乐6折,小说5折
因为不属于商品本身,属于商店营销策略,所以通常的做法是在buy方法是使用if-else判断来源渠道后确定折扣
访问者模式的核心思想是保持容器(商店)内部的元素(商品)不变的前提下,增加对容器内元素的操作。
所以,可以定义一个新的接口Visit确定访问策略
/**
* 每个访问者都要实现这个接口确定自己的折扣
* */
public interface Visitor {
//购买视频时的折扣
public int getDiscount(Video v);
//购买音乐时的折扣
public int getDiscount(Music m);
//购买小说时的折扣
public int getDiscount(Story s);
}
/**
* 商品
* */
public abstract class Product {
//视频名称
String name;
//价格
int price;
//商品购买,此时传入Visitor对象,根据不同的Visitor实现对象确定折扣,同时不影响容器内元素本身
public abstract void buy(Visitor v);
}
/**
*视频
* */
public class Video extends Product{
public Video(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(Visitor v){
//确定折扣
int discount = v.getDiscount(this);
System.out.println(name+"以"+(price*discount)/100+"成交");
}
}
/**
* 音乐
* */
public class Music extends Product{
public Music(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(Visitor v){
int discount = v.getDiscount(this);
System.out.println(name+"以"+(price*discount)/100+"成交");
}
}
/**
* 小说
* */
public class Story extends Product{
public Story(String name,int price){
this.name = name;
this.price = price;
}
@Override
public void buy(Visitor v){
int discount = v.getDiscount(this);
System.out.println(name+"以"+(price*discount)/100+"成交");
}
}
此时,这个系统就已经准备好了。后续并不需要改动系统代码,完成不修改容器内元素的前提下对容器内元素增加操作
/**
* 来自淘宝的访问者
* */
public class TaobaoVisitor implements Visitor {
//淘宝过来的客户购买视频的折扣
@Override
public int getDiscount(Video v) {
return 80;
}
//淘宝过来的客户购买音乐的折扣
@Override
public int getDiscount(Music m) {
return 70;
}
//淘宝过来的客户购买小说的折扣
@Override
public int getDiscount(Story s) {
return 60;
}
}
此时,所有淘宝过来的客户已经可以打折购买商品了,它只是实现了Visitor接口,并没有对容器内的元素做任何修改
/**
* 来自京东的访问者
* */
public class JingDongVisitor implements Visitor {
//京东过来的客户购买视频的折扣
@Override
public int getDiscount(Video v) {return 90;}
//京东过来的客户购买视频的折扣
@Override
public int getDiscount(Music m) {return 80;}
//京东过来的客户购买视频的折扣
@Override
public int getDiscount(Story s) {return 70;}
}
此时,所有京东过来的客户已经可以打折购买商品了。
/**
* 来自拼多多的访问者
* */
public class PinDuoDuoVisitor implements Visitor {
//拼多多过来的客户购买视频的折扣
@Override
public int getDiscount(Video v) {
return 70;
}
//拼多多过来的客户购买视频的折扣
@Override
public int getDiscount(Music m) {
return 60;
}
//拼多多过来的客户购买视频的折扣
@Override
public int getDiscount(Story s) {
return 50;
}
}
此时,所有拼多多过来的客户已经可以打折购买商品了。
访问者模式适用于内部元素结构稳定的容器,一旦商店容器变化,新增商品或者商品改变,Visitor就要改,所有Visitor的实现也要改。