访问者设计模式的思想和案例实现【行为型】

访问者模式是一种行为型设计模式,它可以将算法与对象结构分离开来,使得算法可以独立于对象来变化。该模式主要解决的问题是在不修改对象自身的基础上,对对象的结构进行增删改等操作。

在访问者模式中,对象结构包含多个具体元素,每个具体元素都可以接受一个访问者进行访问,而访问者可以对不同的具体元素进行不同的操作。

在此过程中,访问者可以通过访问具体元素所提供的接口来访问和操作具体元素。

访问者模式的组成要素如下:

  1. 抽象访问者(Visitor):定义了针对不同元素类实现的具体操作方法,是访问者模式的核心。抽象访问者中定义的方法数量取决于元素类所需完成的操作种类。

  2. 具体访问者(Concrete Visitor):实现了抽象访问者中定义的所有方法,并完成对应操作。

  3. 抽象元素类(Element):提供一个接受访问者的接口,并定义了一个 accept() 方法。因此,所有具体元素类都必须继承自该类,并实现 accept() 方法。

  4. 具体元素类(Concrete Element):实现了抽象元素类所定义的 accept() 方法,通常会将自己作为参数传递给访问者,以便访问者能够访问自己。

  5. 对象结构(Object Structure):包含多个具体元素类的集合,提供了遍历其中元素的方法,并将遍历的任务委托给访问者对象。在实际应用中,可能会使用各种数据结构来作为对象结构。

案例:

假设我们有一个图形界面系统,其中包含多种类型的图形元素,如矩形、圆形、文本框等,这些图形元素都具有不同的属性和位置,我们希望能够根据不同的需求对这些图形元素进行不同的操作,如计算它们的面积、计算它们的周长等等。

代码实现:

1、首先我们需要定义图形元素的基本接口,包括接受访问者的方法:

/**
 * 抽象元素,需要访问的对象
 **/
interface Element {
    /**
     * 元素指派方法,将元素指派给某个访问者对象
     * @param visitor 访问者对象
     **/
    void accept(Visitor visitor);
}

2、然后我们定义几个具体访问类,具体的图形元素,如矩形、圆形和文本框。

/**
 * 具体访问元素,圆
 **/
public class Circle implements Element {
​
    /**
     * 确定圆的因素,原点坐标和半径
     **/
    private int x, y, radius;
​
    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }
​
    public int getX() {
        return x;
    }
​
    public int getY() {
        return y;
    }
​
    public int getRadius() {
        return radius;
    }
​
    /**
     * 将圆指派给某个访问者对象
     **/
    @Override
    public void accept(Visitor visitor) {
        visitor.visitCircle(this);
    }
}
​
public class Rectangle implements Element {
​
    private int x, y, width, height;
​
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
​
    public int getX() {
        return x;
    }
​
    public int getY() {
        return y;
    }
​
    public int getWidth() {
        return width;
    }
​
    public int getHeight() {
        return height;
    }
​
    @Override
    public void accept(Visitor visitor) {
        visitor.visitRectangle(this);
    }
}
​
​
public class TextBox implements Element {
​
    private int x, y, width, height;
​
    public TextBox(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
​
    public int getX() {
        return x;
    }
​
    public int getY() {
        return y;
    }
​
    public int getWidth() {
        return width;
    }
​
    public int getHeight() {
        return height;
    }
​
    @Override
    public void accept(Visitor visitor) {
        visitor.visitTextBox(this);
    }
}
​

3、接下来,我们定义一个访问者接口,包含对每个具体图形元素的访问方法:

/**
 * 抽象访问者接口,提供不同元素访问接口
 **/
interface Visitor {
    /**
     * 接收矩形的访问
     **/
    void visitRectangle(Rectangle rectangle);
​
    /**
     * 接收圆的访问
     **/
    void visitCircle(Circle circle);
​
    /**
     * 接收文本框的访问
     **/
    void visitTextBox(TextBox textBox);
}

4、最后,我们定义具体的访问者实现,实现访问所需的具体操作:

/**
 * 计算面积的访问者,提供每一种元素的面积计算方法
 **/
public class AreaCalculator implements Visitor {
​
    private double area;
​
    public double getArea() {
        return area;
    }
​
    @Override
    public void visitRectangle(Rectangle rectangle) {
        area = rectangle.getWidth() * rectangle.getHeight();
    }
​
    @Override
    public void visitCircle(Circle circle) {
        area = Math.PI * circle.getRadius() * circle.getRadius();
    }
​
    @Override
    public void visitTextBox(TextBox textBox) {
        // do nothing
    }
}
​
/**
 * 计算周长的访问者,提供每一种元素的周长计算方法
 **/
public class PerimeterCalculator implements Visitor {
​
    private double perimeter;
​
    public double getPerimeter() {
        return perimeter;
    }
​
    @Override
    public void visitRectangle(Rectangle rectangle) {
        perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());
    }
​
    @Override
    public void visitCircle(Circle circle) {
        perimeter = 2 * Math.PI * circle.getRadius();
    }
​
    @Override
    public void visitTextBox(TextBox textBox) {
        // do nothing
    }
}
​

5、在客户端中,我们可以根据需要选择合适的访问者进行访问操作:

public static void main(String[] args) {
    //声明三个具体的徒刑
    List<Element> elements = new ArrayList<>();
    elements.add(new Rectangle(10, 10, 100, 200));
    elements.add(new Circle(50, 50, 100));
    elements.add(new TextBox(20, 20, 300, 100));
    //声明计算面积访问器和计算周长访问器
    AreaCalculator areaCalc = new AreaCalculator();
    PerimeterCalculator perimeterCalc = new PerimeterCalculator();
​
    //使用访问器一次计算所有图形的周长和面积
    for (Element element : elements) {
        element.accept(areaCalc);
        element.accept(perimeterCalc);
        System.out.println("area = " + areaCalc.getArea());
        System.out.println("周长 = " + perimeterCalc.getPerimeter());
        //初始化 面积和周长计算器
        areaCalc = new AreaCalculator();
        perimeterCalc = new PerimeterCalculator();
        System.out.println("-------------分割-----------------");
    }
​
}
​
//测试结果
area = 20000.0
周长 = 600.0
-------------分割-----------------
area = 31415.926535897932
周长 = 628.3185307179587
-------------分割-----------------
area = 0.0
周长 = 0.0
-------------分割-----------------
​
Process finished with exit code 0

总之,访问者模式适用于需要对一个复杂的对象结构(如树形结构)进行操作,并且需要在不改变各元素类的前提下增加新的操作的场合。它通过将具体操作封装到访问者类中,实现对被访问对象结构的访问和处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值