访问者模式

什么是访问者模式?

在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

引出:

当你设计一个软件系统时,可能会遇到这样的问题:你需要对一个复杂的数据结构进行多种不同的操作,而且这些操作可能会频繁地变化。举个例子,假设你正在开发一个图形编辑器,用户可以在画布上创建各种形状,比如圆形、矩形、三角形等等。

现在,你需要实现一些功能来处理这些形状,比如计算每个形状的面积、绘制它们、或者进行其他一些操作。问题是,随着需求的变化,你可能会不断地添加新的操作,比如旋转、缩放、填充颜色等等。同时,形状的种类也可能会增加,比如新增了椭圆、星形等等。

在这样的情况下,如何设计软件系统使得在不断变化的操作和形状种类下,系统仍然能够保持灵活性和可扩展性呢?这就是引出访问者模式的现实问题。

通过访问者模式,你可以将操作与对象结构分离开来,每个具体的操作都由一个访问者类实现,这样你就可以轻松地添加新的操作而不必修改对象结构。同时,每个形状类只需要实现一个接受访问者的方法,而不需要知道具体的操作,这样就保持了系统的灵活性和可维护性。

介绍

意图:主要将数据结构与数据操作分离。

主要解决:稳定的数据结构和易变的操作耦合问题。

何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

使用场景: 1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

主要角色
  1. Visitor(访问者):为对象结构中的每个具体元素定义一个访问操作。
  2. ConcreteVisitor(具体访问者):实现每个具体元素的访问操作。
  3. Element(元素):定义一个接受访问者的方法,通常是一个抽象类或接口。
  4. ConcreteElement(具体元素):实现接受操作,并在其中调用访问者对应的访问操作。
  5. ObjectStructure(对象结构):能枚举它的元素,可以提供一个高层接口以允许访问者访问其元素。

C++实现:

下面通过一个具体的例子来展示访问者模式在C++中的实现。假设我们有一个对象结构,包含不同类型的形状(如圆形和矩形),我们希望对这些形状进行不同的操作(如计算面积和绘制)。

1. 定义访问者接口
class Circle;
class Rectangle;

class Visitor {
public:
    virtual void visit(Circle *circle) = 0;
    virtual void visit(Rectangle *rectangle) = 0;
    virtual ~Visitor() = default;
};
2. 定义具体访问者
class AreaVisitor : public Visitor {
public:
    void visit(Circle *circle) override;
    void visit(Rectangle *rectangle) override;
};

class DrawVisitor : public Visitor {
public:
    void visit(Circle *circle) override;
    void visit(Rectangle *rectangle) override;
};
3. 定义元素接口
class Shape {
public:
    virtual void accept(Visitor *visitor) = 0;
    virtual ~Shape() = default;
};
4. 定义具体元素
class Circle : public Shape {
public:
    void accept(Visitor *visitor) override {
        visitor->visit(this);
    }
    double radius;
};

class Rectangle : public Shape {
public:
    void accept(Visitor *visitor) override {
        visitor->visit(this);
    }
    double width, height;
};
5. 实现具体访问者方法
#include <iostream>

void AreaVisitor::visit(Circle *circle) {
    double area = 3.14 * circle->radius * circle->radius;
    std::cout << "Circle Area: " << area << std::endl;
}

void AreaVisitor::visit(Rectangle *rectangle) {
    double area = rectangle->width * rectangle->height;
    std::cout << "Rectangle Area: " << area << std::endl;
}

void DrawVisitor::visit(Circle *circle) {
    std::cout << "Drawing Circle with radius: " << circle->radius << std::endl;
}

void DrawVisitor::visit(Rectangle *rectangle) {
    std::cout << "Drawing Rectangle with width: " << rectangle->width
              << " and height: " << rectangle->height << std::endl;
}
6. 使用访问者模式
int main() {
    Circle circle;
    circle.radius = 5;

    Rectangle rectangle;
    rectangle.width = 4;
    rectangle.height = 6;

    AreaVisitor areaVisitor;
    DrawVisitor drawVisitor;

    circle.accept(&areaVisitor);
    circle.accept(&drawVisitor);

    rectangle.accept(&areaVisitor);
    rectangle.accept(&drawVisitor);

    return 0;
}

访问者模式的优缺点

优点:

  1. 增加新的操作很容易:可以在不改变类的情况下增加新的操作。
  2. 集中相关操作:操作集中在访问者类中,而不是分散在元素类中。

缺点:

  1. 违反单一职责原则:元素类需要了解访问者接口,从而违反单一职责原则。
  2. 增加新的元素困难:如果需要增加新的元素类型,则需要修改所有的访问者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值