什么是访问者模式?访问者模式是类与类之间的双向依赖关系(关系有继承,组合和依赖,相当于父子,朋友和情人)。下面的例子就是双向依赖,比较绕,仔细看看吧
class Shape{
void draw(MyWindow myWindow) {
System.out.println("画一个window");
}
}
class MyWindow{
void draw(Shape shape) {
shape.draw(this);
}
}
public class YiLaiDemo {
public static void main(String[] args) {
MyWindow m=new MyWindow();
m.draw(new Shape());
}
}
这里有两次依赖步骤。
让别人以为MyWindow也有draw功能,不过你看MyWindow定义的方法是draw,明显抄了Shape的方法名。
对外进行魔术表演:当MyWindow很潇洒的对外宣称自己有draw功能,关起门来立马跪下求Shape,还是你还draw吧,我其实是冒充的。
我们来看一个例子,需求是软件能画一个正方形,圆形或线条,那么抽象出来一个公有父类,结构如下:
class SHAPE{
public void draw() {
System.out.println("shape draw"); //公共方法:画图
}
}
class Rectangle extends SHAPE{
public void draw() {
System.out.println("画正方形");
}
}
class Circle extends SHAPE{
public void draw() {
System.out.println("画圆形");
}
}
class Line extends SHAPE{
public void draw() {
System.out.println("画线条");
}
}
public class Test5 {
public static void main(String[] args) {
SHAPE s=new Line();//这里是多态,没问题
s.draw();
}
}
上面都是简单的多态,没问题。
需求变了,现在需要每个图形都可以放大,那么添加一个放大方法,我们可以在父类了添加一个方法方法,子类去覆盖,但这里我们不这样做,用扩展的方式增加方法,代码如下:
class SHAPE{
public void draw() {
System.out.println("shape draw"); //公共方法:画图
}
}
class Rectangle extends SHAPE{
public void draw() {
System.out.println("画正方形");
}
public static void zoomIn(Rectangle c) { //扩展方法:图形变大,这里为什么不写在父类里呢,因为考虑到最低耦合,况且zoonIn没有引用新的成员。
System.out.println("zoomIn Rectangle");
}
}
class Circle extends SHAPE{
public void draw() {
System.out.println("画圆形");
}
public static void zoomIn(Circle c) {
System.out.println("zoomIn Circle");
}
}
class Line extends SHAPE{
public void draw() {
System.out.println("画线条");
}
public static void zoomIn(Line l) {
System.out.println("zoomIn Line");
}
}
public class Test5 {
public static void main(String[] args) {
SHAPE s=new Line();//这里是多态,没问题
s.draw();
if (s instanceof Rectangle) { //要用扩展方法就必须多次判断,这很蛋疼
Rectangle.zoomIn((Rectangle)s);
}else if (s instanceof Circle) {
Circle.zoomIn((Circle)s);
}else if (s instanceof Line) {
Line.zoomIn((Line)s);
}
}
}
针对以上要多次判断的蛋疼问题,访问者模式就出来了。
访问者可以帮助每一个子类去找到对应的扩展方法。
看看下面的代码:
interface IVisitor{
public void visitor(Rectangle rect);
public void visitor(Circle circle);
public void visitor(Line line);
}
class ZoomInVisitro implements IVisitor{
@Override
public void visitor(Rectangle rect) {
// TODO Auto-generated method stub
System.out.println("正方形变大");
}
@Override
public void visitor(Circle circle) {
// TODO Auto-generated method stub
System.out.println("圆形变大");
}
@Override
public void visitor(Line line) {
// TODO Auto-generated method stub
System.out.println("线条变大");
}
}
class SHAPE{
public void draw() {
System.out.println("shape draw");
}
public void AcceptVisitor(IVisitor visitor) {
System.out.println("i an visitor");
}
}
class Rectangle extends SHAPE{
public void draw() {
System.out.println("画正方形");
}
public void AcceptVisitor(IVisitor visitor) {
visitor.visitor(this);
}
}
class Circle extends SHAPE{
public void draw() {
System.out.println("画圆形");
}
public void AcceptVisitor(IVisitor visitor) {
visitor.visitor(this);
}
}
class Line extends SHAPE{
public void draw() {
System.out.println("画线条");
}
public void AcceptVisitor(IVisitor visitor) {
visitor.visitor(this);
}
}
public class Test5 {
public static void main(String[] args) {
SHAPE s=new Line();
s.draw();
s.AcceptVisitor(new ZoomInVisitro());
}
}
ok到这里就完成了访问者模式。
这样非常巧妙的解决了各种if的问题,
为什么要这样做,多此一举,这样改的动静也很大啊!
图的就是应付不断的横向扩展的需求!注意横向扩展是理解很多设计模式的关键。否则你总不理解简单的需求为什么要弄的那么复杂!
考虑要将来,需要一个所有的shape都添加一个缩小方法,那么只要添加ZoomOut接口和相应的实现类。看一下代码吧:
interface Shapes{
public void draw();
public void AcceptVisitor(IVisitor visitor);
}
class Yuan implements Shapes{
public void draw() {
System.out.println("Yuan draw");
}
public void AcceptVisitor(IVisitor visitor) {
// TODO Auto-generated method stub
visitor.zoomIn(this);
}
}
class Fang implements Shapes{
public void draw() {
System.out.println("Fang draw");
}
public void AcceptVisitor(IVisitor visitor) {
// TODO Auto-generated method stub
visitor.zoomIn(this);
}
}
class Xian implements Shapes{
public void draw() {
System.out.println("Xian draw");
}
public void AcceptVisitor(IVisitor visitor) {
// TODO Auto-generated method stub
visitor.zoomIn(this);
}
}
interface IVisitor{
default void zoomIn(Xian xian) {}
default void zoomIn(Yuan yuan) {}
default void zoomIn(Fang fang) {}
default void zoomOut(Xian xian) {}
default void zoomOut(Yuan yuan) {}
default void zoomOut(Fang fang) {}
}
class ZoomIn implements IVisitor {
public void zoomIn(Yuan yuan) {
// TODO Auto-generated method stub
System.out.println("圆变大");
}
public void zoomIn(Fang fang) {
// TODO Auto-generated method stub
System.out.println("方变大");
}
public void zoomIn(Xian xian) {
// TODO Auto-generated method stub
System.out.println("线变大");
}
}
class ZoonOut implements IVisitor{
public void zoomOut(Xian xian) {
// TODO Auto-generated method stub
System.out.println("线变小");
}
@Override
public void zoomOut(Yuan yuan) {
// TODO Auto-generated method stub
System.out.println("圆变小");
}
@Override
public void zoomOut(Fang fang) {
// TODO Auto-generated method stub
System.out.println("方变小");
}
}
public class Test5 {
public static void main(String[] args) {
Shapes s=new Yuan();
s.draw();
s.AcceptVisitor(new ZoomIn());//访问者去寻找圆变大方法
s.AcceptVisitor(new ZoonOut());//访问者去寻找圆变小方法
}
}
再来看一下扩展了zoomout的uml图
这里例子中增加了变小方法,那么就在IVisitor接口中定义三个变小方法,新增一个变小的类去实现接口,覆盖一下方法就可以了。怎么样?是不是更具有扩展性了呢?