Java访问者模式详解(附案例)

什么是访问者模式?访问者模式是类与类之间的双向依赖关系(关系有继承,组合和依赖,相当于父子,朋友和情人)。下面的例子就是双向依赖,比较绕,仔细看看吧

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接口中定义三个变小方法,新增一个变小的类去实现接口,覆盖一下方法就可以了。怎么样?是不是更具有扩展性了呢?

猜你喜欢

转载自blog.csdn.net/weixin_43299461/article/details/86522657