设计模式(十四)——访问者模式(Visitor )
使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。
当一个对象的元素在不同的场景改变较为频繁时,可以使用访问者模式。例如:公园的风景在不同的人的眼中,有人觉得好看,有人觉得不好看。
优点
将数据结构与数据操作分离,有良好的扩展性和灵活性
缺点
1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
实现
有一台电脑,不同的人来买对零件有不同的折扣。学生买CPU打九五折,键盘九折,鼠标八五折,如果是企业大规模购买,CPU八五折,键盘八折,鼠标七五折。
电脑
public class Computer {
float CPUMoney;
float keyboardMoney;
float mouseMoney;
public Computer(float CPUMoney, float keyboardMoney, float mouseMoney) {
this.CPUMoney = CPUMoney;
this.keyboardMoney = keyboardMoney;
this.mouseMoney = mouseMoney;
}
}
购买者,每个购买者都需要实现三个方法,对电脑零件有不同的折扣
public interface Visitor {
public float CPUDiscount(Computer computer);
public float KeyBoardDiscount(Computer computer);
public float MouseDiscount(Computer computer);
}
学生购买者
public class Student implements Visitor{
@Override
public float CPUDiscount(Computer computer) {
return (float) (computer.CPUMoney*0.95);
}
@Override
public float KeyBoardDiscount(Computer computer) {
return (float) (computer.keyboardMoney*0.9);
}
@Override
public float MouseDiscount(Computer computer) {
return (float) (computer.mouseMoney*0.85);
}
}
企业购买者
public class Enterprise implements Visitor{
@Override
public float CPUDiscount(Computer computer) {
return (float) (computer.CPUMoney*0.85);
}
@Override
public float KeyBoardDiscount(Computer computer) {
return (float) (computer.keyboardMoney*0.8);
}
@Override
public float MouseDiscount(Computer computer) {
return (float) (computer.mouseMoney*0.75);
}
}
public class Main {
public static void main(String[] args) {
Computer computer = new Computer(800,100,50);
System.out.println("学生购买CPU价格"+new Student().CPUDiscount(computer));
}
}
运行结果:
如果还有其他类型的购买者,只需要实现Visitor接口即可。但是需要注意,访问者模式中的被访问者需要是元素固定,不会再改变的对象,否则添加对象时非常麻烦。比如电脑类添加了一个屏幕价格的属性,那么所有的代码都需要更改。