c++设计模式概述之访问者

代码写的不够规范,目的是为了缩短篇幅,实际中请注意。

 

参看: http://c.biancheng.net/view/1397.html

 

1、概述

  类比生活中的场景,购物商场中的商品、顾客、收营员。商品针对不同的人员,对商品的操作也是不同的。比如,顾客挑选商品,购买商品, 而收银员则是核对商品价格,针对商品收银。 同样是商品,但是面对不同的人,其操作也是不同的。

访问者模式包含以下主要角色:
  A、抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  B、具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  C、抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  D、具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  E、对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现

  下面以商场购物为例

 

2、抽象访问者类

// 顾客,抽象类
class visitor
{
public:
    void set_name(std::string name) { _str_name = name; }

    // 访问商品
    virtual void visit(bowel *pbowel)        = 0;
    virtual void visit(chicken *pchicken)    = 0;
    std::string get_name() { return _str_name; };
protected:
    std::string _str_name;
};

 

3、抽象商品类

// 抽象商品类
class product
{
public:
    virtual void accept(visitor *pvisitor) = 0;
};

 

4、具体产品类

  这里准备了碗和鸡肉两种商品

// 碗,一个具体的商品类
class bowel : public product
{
public:
    void accept(visitor *pvisitor)
    {
        if (pvisitor)
            pvisitor->visit(this);
    }
};

// 鸡肉,一个具体的商品类
class chicken : public product
{
public:
    void accept(visitor *pvisitor)
    {
        if (pvisitor)
            pvisitor->visit(this);
    }
};

 

5、具体的访问者

  这里实现了顾客和收银员

// 顾客A
class customerA : public visitor
{
public:
    void visit(bowel *pbowel)
    {
        if (pbowel)
            std::cout << _str_name << "正在挑选-碗\n";
    }

    void visit(chicken *pchicken)
    {
        if (pchicken)
            std::cout << _str_name << "正在挑选-鸡肉\n";
    }
};

//收银员
class saler : public visitor
{
public:
    void visit(bowel *pbowel)
    {
        if (pbowel)
            std::cout << _str_name << "正在扫描商品-碗\n";
    }

    void visit(chicken *pchicken)
    {
        if (pchicken)
            std::cout << _str_name << "正在扫描商品-鸡肉\n";
    }
};

 

6、对象结构类

  这里以购物车为例

// 购物车, 对象结构
class shopping_cart
{
public:
    // 可以添加商品到购物车
    void add(product *ppd) 
    {
        if (ppd)
        {
            _list_product.push_back(ppd);
            std::cout << "\n购物车:添加商品成功\n";
        }
    }
    
    // 可以从购物车删除商品
    void remove(product* ppd)
    {
        // 1、要删除的商品不存在
        if (!ppd)
        {
            std::cout << "\n购物车:商品删除失败,待删除的商品不存在\n";
            return;
        }

        // 2、找下,购物车是否存在该商品
        std::list<product*> ::iterator& it = std::find(_list_product.begin(), _list_product.end(), ppd);
        // 找到了,再删除
        if (_list_product.end() != it)
        {
            _list_product.remove(ppd);
            std::cout << "\n购物车:成功移除商品\n";
        }
        else
            std::cout << "\n购物车:删除商品失败,没有找到该商品\n";
    }

    void accept(visitor *pvisitor)
    {
        if (!pvisitor)
            return;

        for each(auto item in _list_product)
        {
            item->accept(pvisitor);
        }
    }

private:
    // 购物车,可以存放很多商品,
    std::list<product*> _list_product;
};

 

7、调用

void call_visitor()
{
    // 1、商场准备上架商品
    bowel bw1;
    bowel bw2;

    chicken ck1;
    chicken ck2;

    // 2、再给客户准备购物车,方便购物
    shopping_cart sc;

    // 消费者A + 商场服务对象
    customerA customa;
    customa.set_name(std::string("顾客A"));
    saler    salerZ;
    salerZ.set_name(std::string("收银员Z"));

    // 3、顾客挑选商品
    // 3.1、顾客需要购物车
    sc.accept(&customa);
    // 3.2、将选好的商品放入购物车
    std::cout << "\n---------------------------------\n";
    customa.visit(&bw1);
    sc.add(&bw1);

    std::cout << "\n---------------------------------\n";
    customa.visit(&bw2);
    sc.add(&bw2);
    
    std::cout << "\n---------------------------------\n";
    sc.add(&ck1);
    customa.visit(&ck1);

    std::cout << "\n---------------------------------\n";
    sc.add(&ck2);
    customa.visit(&ck2);
    std::cout << "\n---------------------------------\n";

    // 4、商品买多了? 移除
    std::cout << customa.get_name() << "\n正在移除商品\n";
    sc.remove(&ck2);

    std::cout << "\n-------------------------\n选购结束,准备结算:\n";
    // 5、这时,购物车是由收银员check
    sc.accept(&salerZ);
}

 

8、结果

 

posted @ 2020-08-15 10:30  mohist  阅读(174)  评论(0编辑  收藏  举报