189 8069 5689

设计者模式(1)观察者模式(Observer)C++11实现-创新互联

意图

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
该模式属于行为型模式。

创新互联为您提适合企业的网站设计 让您的网站在搜索引擎具有高度排名,让您的网站具备超强的网络竞争力!结合企业自身,进行网站设计及把握,最后结合企业文化和具体宗旨等,才能创作出一份性化解决方案。从网站策划到成都网站制作、网站设计, 我们的网页设计师为您提供的解决方案。参与者
  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个或者多个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者者的抽象类,它定义了一个或者多个更新接口,使得在得到主题更改通知时更新自己。
  • ConcreteObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
优点
  • 观察者模式可以实现表示层和数据逻辑层的分离,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色
  • 观察者模式在观察目标和观察者之间建立一个抽象的耦合
  • 观察者模式支持广播通信
缺点
  • 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,将所有的观察者都通知到会花费很多时间。如果考虑到性能问题,可以实现一个异步非阻塞的观察者模式,在每次fire subject的时候创建一个新的线程执行代码。

  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

代码实现
#include#include#include#include#includeclass Observer;
typedef std::vector>::iterator Iterator;//迭代器

//抽象被观察者
class Subject
{public:
    virtual void Attach(std::weak_ptr)=0;//注册观察者对象的接口
    virtual Iterator Detach(Iterator it)=0;//删除观察者对象的接口
    virtual void notifyObservers()=0;//告知所有观察者update
};

//抽象观察者

class Observer
{public:
    virtual void update()=0;//更新自身状态
};

//被观察者
class ConcreteSubject :public::Subject
{public:
    void Attach(std::weak_ptrs)
    {//vector的add是线程安全的
        observers_.push_back(s);
    }
    Iterator Detach(Iterator it)
    {//线程不安全,要在临界区调用此接口
        return observers_.erase(it);
    }

    void notifyObservers()
    {lock.lock();
        Iterator it=observers_.begin();
        while(it!=observers_.end())
        {//先尝试将weak_ptr提升为share_ptr
            std::shared_ptrobj=it->lock();
            if(obj)//提升成功,说明该对象未被其他线程析构
            {obj->update();//更新
                ++it;
            }
            else//提升失败,说明该对象已被其他线程析构
            {//从观察者集合中将已被析构对象删除
                //因为此处属于临界区,是线程安全的
                it=Detach(it);
            }

        }
        lock.unlock();
    }
    
private:
    mutable std::mutex lock;
    std::vector>observers_;//观察者集合

};

//观察者按需求定义即可,需要继承抽象观察者
//以下为例
class Teacher :public::Observer
{public:
    void update()
    {std::cout<<"Teacher is update"<std::cout<<"Teacher is ~"<public:
    void update()
    {std::cout<<"Student is update"<std::cout<<"Student is ~"<

测试

int main()
{ConcreteSubject subject;
    
    std::shared_ptrteacher(new Teacher);
    subject.Attach(teacher);
    {std::shared_ptrstudent(new Student);
        subject.Attach(student);
        subject.notifyObservers();
    }


    subject.notifyObservers();

}

执行结果

Teacher is update
Student is update
Student is ~
Teacher is update
Teacher is ~
迭代器失效问题分析

在学习该模型时,遇到了一个bug,问题锁定在notifyObservers()当中,当时的实现如下

void notifyObservers()
{lock.lock();
    Iterator it=observers_.begin();
    while(it!=observers_.end())
    {std::shared_ptrobj=it->lock();
        if(obj)
        {obj->update();
        }
        else
        {Detach(it);
        }
        it++;
    }
}

当时执行main时,就会报段错误,经过检查不难发现,问题是迭代器失效了

删除导致迭代器失效

这个问题其实很好分析,在一顺序容器当中(vector,queue…等),数据是顺序存储的,当删除一个元素后,内存中的数据会往前移动,以保证数据的紧凑。所以删除一个元素后,该元素后面的其他元素的地址都会发生改变。在删除操作前所持有的迭代器就会有失效的可能。看下面的例子。

#include#include#includeusing namespace std;
int main()
{  vectorarr;
  arr.push_back(1);
  arr.push_back(2);
  arr.push_back(3);
  arr.push_back(4);
  arr.push_back(5);

  vector::iterator it=arr.begin()+3;

  cout<<"删除操作前该迭代器所指向的元素:"<

执行结果如下

删除操作前该迭代器所指向的元素:
4
进行删除操作
删除操作前该迭代器所指向的元素:
5
添加导致迭代器失效

你的添加的操作也是可能导致迭代器失效的。vector的容量是动态的开辟的,当容量不够的话,会进行realloc操作进行扩容,若该数组的后面的空间不足,realloc函数会找一片更大的空间,将原数据拷贝进去。若在此事件发生前,获取一个迭代器,此事件发生后,该迭代器会失效。看下面例子

#include#include#includeusing namespace std;
int main()
{  vectorarr;
  arr.push_back(1);
  arr.push_back(2);
  arr.push_back(3);
  arr.push_back(4);
  arr.push_back(5);

  vector::iterator it=arr.begin()+3;

  cout<<"此事件发生前该迭代器所指向的元素:"<arr.push_back(9);
  }
  cout<<"此事件发生后该迭代器所指向的元素:"<

执行结果

此事件发生前该迭代器所指向的元素:
4
此事件发生后该迭代器所指向的元素:
21854

此时该迭代器就指向一个未初始化的空间

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网站栏目:设计者模式(1)观察者模式(Observer)C++11实现-创新互联
URL地址:http://cdxtjz.cn/article/djhccg.html

联系我们

您好HELLO!
感谢您来到成都网站建设公司,若您有合作意向,请您为我们留言或使用以下方式联系我们, 我们将尽快给你回复,并为您提供真诚的设计服务,谢谢。
  • 电话:028- 86922220 18980695689
  • 商务合作邮箱:631063699@qq.com
  • 合作QQ: 532337155
  • 成都网站设计地址:成都市青羊区锣锅巷31号五金站写字楼6楼

小谭建站工作室

成都小谭网站建设公司拥有多年以上互联网从业经验的团队,始终保持务实的风格,以"帮助客户成功"为已任,专注于提供对客户有价值的服务。 我们已为众企业及上市公司提供专业的网站建设服务。我们不只是一家网站建设的网络公司;我们对营销、技术、管理都有自己独特见解,小谭建站采取“创意+综合+营销”一体化的方式为您提供更专业的服务!

小谭观点

相对传统的成都网站建设公司而言,小谭是互联网中的网站品牌策划,我们精于企业品牌与互联网相结合的整体战略服务。
我们始终认为,网站必须注入企业基因,真正使网站成为企业vi的一部分,让整个网站品牌策划体系变的深入而持久。