当前位置: 首页 > wzjs >正文

erp外贸管理系统宁波seo推荐

erp外贸管理系统,宁波seo推荐,展示型网站建设标准,长沙 外贸网站建设公司五、观察者模式 在程序设计中,需要为某对象建立一种“通知依赖关系”,当该对象的状态发生变化时,通过公告或广播的方式通知一系列相关对象,实现对象之间的联动。但这种一对多的对象依赖关系往往会造成该对象与其相关的一系列对象…

五、观察者模式

在程序设计中,需要为某对象建立一种“通知依赖关系”,当该对象的状态发生变化时,通过公告或广播的方式通知一系列相关对象,实现对象之间的联动。但这种一对多的对象依赖关系往往会造成该对象与其相关的一系列对象之间一种特别紧密的耦合关系。
观察者(Observer)模式是一种使用频率较高的行为型设计模式,可以弱化上述的一对多依赖关系,实现对象之间关系的松耦合。观察者模式在工作中往往会在不知不觉中被用到。

5.1 一个遍历问题导致的低效率范例

A 公司开发的单机闯关打斗类游戏因为收益日渐减少,公司举步维艰。看到隔壁 B 公司开发的网络游戏做得风生水起,A 公司的老板决定将这款单机闯关打斗类游戏改造成类似于《魔兽世界》的大型多人角色扮演类游戏(网络游戏),以往单机游戏中的主角变成了游戏中的每个玩家。游戏本身是不收费的,但游戏中的各种道具(例如药品等)是要收费的。这种对项目的改造要投入巨大的人力、物力以及时间成本,项目组又扩充了数名熟悉网络游戏开发的程序员。
某日,策划召集项目组全体人员开会增加新的游戏玩法,核心内容如下:

  1. 为增加游戏收入,必须实现游戏中玩家群体之间的战争,因为战争会消耗游戏中的各种物资,例如补充生命值或补充魔法值的药品等。为此,引入“家族”概念,玩家可以自由加入某个家族,一个家族最多容纳20个玩家,不同家族的玩家之间可以根据游戏规则在指定时间和地点通过战斗获取利益。
  2. 家族成员的聊天信息会被家族中的所有其他成员看到,当然,家族其他成员有权屏蔽家族的聊天信息。非本家族的玩家是看不到本家族成员聊天信息的。

策划要求程序率先实现家族成员聊天功能。于是,程序开始了第一版的开发工作,代码如下:

第一版代码实现

// 玩家父类(以往的战斗者父类)
class Fighter {
public:Fighter(int tmpID, string tmpName) : m_iPlayerID(tmpID), m_sPlayerName(tmpName) {m_iFamilyID = -1;  // -1表示没加入任何家族}virtual ~Fighter() {}  // 析构函数public:void SetFamilyID(int tmpID) {m_iFamilyID = tmpID;  // 加入家族时设置家族ID}private:int m_iPlayerID;        // 玩家ID,全局唯一string m_sPlayerName;   // 玩家名字int m_iFamilyID;        // 家族ID
};// "战士"类玩家,父类为Fighter
class F_Warrior : public Fighter {
public:F_Warrior(int tmpID, string tmpName) : Fighter(tmpID, tmpName) {}  // 构造函数
};// "法师"类玩家,父类为Fighter
class F_Mage : public Fighter {
public:F_Mage(int tmpID, string tmpName) : Fighter(tmpID, tmpName) {}  // 构造函数
};

在文件头增加全局玩家列表:

#include <list>
class Fighter;  // 类前向声明
list<Fighter*> g_playerList;

Fighter 类中添加聊天功能:

public:
void SayWords(string tmpContent) {if (m_iFamilyID != -1) {  // 该玩家属于某个家族for (auto iter = g_playerList.begin(); iter != g_playerList.end(); ++iter) {if (m_iFamilyID == (*iter)->m_iFamilyID) {NotifyWords(*iter, tmpContent);  // 通知同家族玩家}}}
}private:
void NotifyWords(Fighter* otherPlayer, string tmpContent) {cout << " 玩家:" << otherPlayer->m_sPlayerName << " 收到了玩家:" << m_sPlayerName << " 发送的聊天信息:" << tmpContent << endl;
}

测试代码

Fighter* pplayerobj1 = new F_Warrior(10, "张三");
pplayerobj1->SetFamilyID(100);
g_playerList.push_back(pplayerobj1);Fighter* pplayerobj2 = new F_Warrior(20, "李四");
pplayerobj2->SetFamilyID(100);
g_playerList.push_back(pplayerobj2);Fighter* pplayerobj3 = new F_Mage(30, "王五");
pplayerobj3->SetFamilyID(100);
g_playerList.push_back(pplayerobj3);Fighter* pplayerobj4 = new F_Mage(50, "赵六");
pplayerobj4->SetFamilyID(200);
g_playerList.push_back(pplayerobj4);pplayerobj1->SayWords(" 全族人立即到沼泽地集结,准备进攻!");

执行结果

玩家:张三 收到了玩家:张三发送的聊天信息:全族人立即到沼泽地集结,准备进攻!
玩家:李四收到了玩家:张三发送的聊天信息:全族人立即到沼泽地集结,准备进攻!
玩家:王五收到了玩家:张三发送的聊天信息:全族人立即到沼泽地集结,准备进攻!

5.2 引入观察者模式

如果把隶属于某个家族的所有玩家收集到一个列表中,当该家族中的某个玩家发出一条聊天信息后,只需遍历该玩家所在家族的列表,效率更高。以下是优化后的代码:

优化后的代码实现

// 通知器父类
class Notifier {
public:virtual void addToList(Fighter* player) = 0;virtual void removeFromList(Fighter* player) = 0;virtual void notify(Fighter* talker, string tmpContent) = 0;virtual ~Notifier() {}
};// 玩家父类
class Fighter {
public:Fighter(int tmpID, string tmpName) : m_iPlayerID(tmpID), m_sPlayerName(tmpName) {m_iFamilyID = -1;}virtual ~Fighter() {}public:void SetFamilyID(int tmpID) { m_iFamilyID = tmpID; }int GetFamilyID() { return m_iFamilyID; }void SayWords(string tmpContent, Notifier* notifier) {notifier->notify(this, tmpContent);}virtual void NotifyWords(Fighter* talker, string tmpContent) {cout << " 玩家:" << m_sPlayerName << " 收到了玩家:" << talker->m_sPlayerName << " 发送的聊天信息:" << tmpContent << endl;}private:int m_iPlayerID;string m_sPlayerName;int m_iFamilyID;
};// 聊天信息通知器
class TalkNotifier : public Notifier {
public:void addToList(Fighter* player) override {int tmpfamilyid = player->GetFamilyID();if (tmpfamilyid != -1) {auto iter = m_familyList.find(tmpfamilyid);if (iter != m_familyList.end()) {iter->second.push_back(player);} else {list<Fighter*> tmpplayerlist;m_familyList.insert(make_pair(tmpfamilyid, tmpplayerlist));m_familyList[tmpfamilyid].push_back(player);}}}void removeFromList(Fighter* player) override {int tmpfamilyid = player->GetFamilyID();if (tmpfamilyid != -1) {auto iter = m_familyList.find(tmpfamilyid);if (iter != m_familyList.end()) {m_familyList[tmpfamilyid].remove(player);}}}void notify(Fighter* talker, string tmpContent) override {int tmpfamilyid = talker->GetFamilyID();if (tmpfamilyid != -1) {auto itermap = m_familyList.find(tmpfamilyid);if (itermap != m_familyList.end()) {for (auto iterlist = itermap->second.begin(); iterlist != itermap->second.end(); ++iterlist) {(*iterlist)->NotifyWords(talker, tmpContent);}}}}private:map<int, list<Fighter*>> m_familyList;  // 家族ID -> 玩家列表
};

测试代码

Fighter* pplayerobj1 = new F_Warrior(10, "张三");
pplayerobj1->SetFamilyID(100);Fighter* pplayerobj2 = new F_Warrior(20, "李四");
pplayerobj2->SetFamilyID(100);Fighter* pplayerobj3 = new F_Mage(30, "王五");
pplayerobj3->SetFamilyID(100);Fighter* pplayerobj4 = new F_Mage(50, "赵六");
pplayerobj4->SetFamilyID(200);Notifier* ptalknotify = new TalkNotifier();
ptalknotify->addToList(pplayerobj1);
ptalknotify->addToList(pplayerobj2);
ptalknotify->addToList(pplayerobj3);
ptalknotify->addToList(pplayerobj4);pplayerobj1->SayWords(" 全族人立即到沼泽地集结,准备进攻!", ptalknotify);cout << " 王五不想再收到家族其他成员的聊天信息了---" << endl;
ptalknotify->removeFromList(pplayerobj3);
pplayerobj2->SayWords(" 请大家听从族长的调遣,前往沼泽地!", ptalknotify);

执行结果

玩家:张三 收到了玩家:张三发送的聊天信息:全族人立即到沼泽地集结,准备进攻!
玩家:李四收到了玩家:张三发送的聊天信息:全族人立即到沼泽地集结,准备进攻!
玩家:王五 收到了玩家:张三 发送的聊天信息:全族人立即到沼泽地集结,准备进攻!
王五不想再收到家族其他成员的聊天信息了---
玩家:张三收到了玩家:李四发送的聊天信息:请大家听从族长的调遣,前往沼泽地!
玩家:李四收到了玩家:李四发送的聊天信息:请大家听从族长的调遣,前往沼泽地!

观察者模式UML图

图5.1 抽象通知器的UML图
继承
继承
继承
聚合(观察者列表)
聚合(观察者列表)
Notifier
+addToList()
+removeFromList()
+notify()
TalkNotifier
+addToList()
+removeFromList()
+notify()
«abstract»
Fighter
+NotifyWords()
F_Warrior
+NotifyWords()
F_Mage
+NotifyWords()
图5.2 非抽象通知器的UML图
继承
继承
聚合(观察者列表)
TalkNotifier
+addToList()
+removeFromList()
+notify()
«abstract»
Fighter
+NotifyWords()
F_Warrior
+NotifyWords()
F_Mage
+NotifyWords()
图5.3 观察者模式角色关系图

观察者模式角色关系图

5.3 应用联想

  1. 游戏救援通知
    家族成员被攻击时,通知其他成员救援(如《征途》镖车救援)。

  2. 新闻推送系统
    门户网站根据用户兴趣推送新闻(国际/娱乐/美食等)。

  3. 数据可视化
    销售数据变化时,更新饼图、柱状图、折线图。

  4. 游戏AI攻击
    炮楼监视玩家距离,30米内自动攻击。

观察者模式特点

  1. 松耦合:依赖抽象而非具体类,符合依赖倒置原则。
  2. 广播通知:观察目标主动通知观察者,简化一对多设计。
  3. 开闭原则:新增观察者或观察目标时,无需修改现有代码。
http://www.dtcms.com/wzjs/254431.html

相关文章:

  • 怎么自己建设网站搜索引擎优化营销
  • 韩城做网站百度搜索关键词排名
  • 西安做网站比较好的公司网络广告策划书
  • 一键安装 wordpress搜索引擎优化的对比
  • 河北品牌网站建设西安做网站
  • 教育网站制作哪个好百度竞价排名
  • 电商类网站建设需要多少钱郑州网站推广优化
  • 阜新市建设学校管方网站淄博头条新闻今天
  • wordpress linux版本专业seo服务商
  • 政府网站建设文件汇编北京百度关键词排名
  • 90后做网站月入万元站长工具搜索
  • 西安 医疗网站制作海外建站
  • 贵港公司做网站新网站百度收录
  • 如果做动态网站开发 以下搜索引擎优化的缺点包括
  • 郑州做网站哪个新站seo优化快速上排名
  • 优秀网站展示自媒体视频剪辑培训班
  • 建设银行网站上改手机泰安优化关键词排名哪家合适
  • 微信网站用什么制作的短视频营销推广
  • 竹子林网站建设关键词推广计划
  • wordpress 点点模版seo软文推广工具
  • 黄石网站建设维护排名优化
  • 好用的在线设计网站北京网站优化合作
  • 自己做的网站源码如何安装谷歌的推广是怎么样的推广
  • 做网站难不难seo建站是什么意思
  • 网站建设业务范围知乎推广公司
  • 服务器用来做网站空间今天的新闻
  • 武汉专业外贸网站制作维护php视频转码
  • fastcomet wordpress宝鸡seo培训
  • 溧阳网站建设广告联盟自动挂机赚钱
  • 响应式网站预览北京谷歌seo公司