在王者荣耀角度下分析面向对象程序设计B中23种设计模式之观察者模式

·

观察者模式在王者荣耀中的应用

·

系统提示:摧毁敌方防御塔

一、简述

王者荣耀是一款5v5的团队竞技游戏,在一局游戏当中,必要的系统提示有利于玩家对实时的战况有更好地把握。比如,当游戏开局时,系统会提示“敌军还有5秒到达战场,请做好准备”;当有英雄被击杀时或者敌我双方防御塔被摧毁时,我方队友和敌方收到的系统提示是不同的。
于是,此类问题就可以用观察者模式很好的实现当防御塔被摧毁后敌我双方英雄分别收到不同的消息的结果。这里再简单描述一下这个具体问题:当敌方高低防御塔被我方娜可露露摧毁时,我方全部队友收到系统提示消息“(娜可露露)摧毁敌方防御塔”,而敌方英雄收到的则是“(娜可露露)摧毁我方防御塔”。

这里所述的
“摧毁防御塔”相当于观察者模式中的一个具体“主题”
“敌我双方每位英雄”相当于观察者模式中的一个具体“观察者”

二、观察者模式(Observer Pattern)

观察者模式理解:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
观察者模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

观察者模式结构中的四种角色:
主题(Subject):是一个接口,规定了具体主题需要实现的方法
观察者(Observer): 是一个接口,规定了具体观察者用来更新数据的方法
具体主题(ConcreteSubject) :是实现主题接口类的一个实例
具体观察者(ConcreteObserver):是实现观察者接口类的一个实例

观察者模式的UML类图:
在这里插入图片描述
观察者模式的优缺点:
优点:
①容易扩展
②满足“开—闭原则”
③具体主题和具体观察者是松耦合关系
缺点:
①多级触发效率较低
②因为是顺序执行,一个观察者卡壳,会影响整体的执行效率

三、王者荣耀角度下实现观察者模式结构图及代码

实现此观察者模式的UML类图在这里插入图片描述

eclipse结构图
在这里插入图片描述
主函数【应用(Application)】

package angle_observer;

import angle_observer.TeammatesReceive;
import angle_observer.TurretBeenDestroyed;

/*
使用了观察者模式中所涉及的类,应用程序在使用观察者模式时,需要创建具体主题和该主题的观察者
当系统消息提示“敌方防御塔被摧毁”时,我方和敌方分别得到内容不同的通知  
*/

public class Application {
public static void main(String args[]){
	TurretBeenDestroyed message=new TurretBeenDestroyed(); //具体主题message
	System.out.println(" ");
	TeammatesReceive teammates=new TeammatesReceive(message,"收到系统消息");  //具体观察者teammates
	EnemiesReceive enemies=new EnemiesReceive(message,"收到系统消息");    //具体观察者enemies
	message.giveNewMess("“敌方防御塔被摧毁”");       //具体主题给出新信息
	message.notifyObservers();                   //具体主题通知信息
}

}

主题接口
Subject.java

package angle_observer;

import angle_observer.Observer;

/*
角色1:主题:是一个接口,规定了具体主题需要实现的方法
          如:添加、删除观察者以及通知观察者更新数据的方法 
*/

public interface Subject {
	public void addObserver(Observer o);    //规定了具体主题需要实现的添加观察者更新数据的方法
	public void deleteObserver(Observer o);    //规定了具体主题需要实现的删除观察者更新数据的方法
	public void notifyObservers();          //规定了具体主题需要实现的通知观察者更新数据的方法


}

观察者接口
Observer.java

package angle_observer;

/*
角色2:观察者:是一个接口,规定了具体观察者用来更新数据的方法 
*/

public interface Observer {
	public void hearMessage(String mess);   //相当于观察者模式类图中的update()方法
//要求观察者都通过实现hearMessage()方法(模拟接收系统消息)来更新数据

}

具体主题
TurretBeenDestroyed.java

package angle_observer;

/*
角色3:具体主题:是实现主题接口类的一个实例(包含可能经常发生变化的数据)
              具体主题需要使用一个集合如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。 
*/

import java.util.ArrayList;

public class TurretBeenDestroyed implements Subject{
     String mess;               //用来表示队友接收到的消息内容
     boolean changed;
     ArrayList<Observer>informationList;   //存放观察者引用的数组线性表
     TurretBeenDestroyed(){
	        informationList=new ArrayList<Observer>();
	        mess="";
	        changed=false;
       }
     public void addObserver(Observer o){
	      if(!(informationList.contains(o)))
	    	    informationList.add(o);        //把观察者的引用添加到数组线性表
             }
     public void deleteObserver(Observer o){
	      if(informationList.contains(o))
	    	    informationList.remove(o);       
             }
     public void notifyObservers(){
	      if(changed){                  //通知所有的观察者
		        for(int i=0;i<informationList.size();i++){  //遍历具体主题中用来存放观察者引用的集合
			          Observer observer=informationList.get(i);
			          observer.hearMessage(mess);    //让观察者接收系统消息(执行观察者接口规定更新数据的方法)
		           }
		        changed=false;
	        }
         }
     public void giveNewMess(String str){
	       if(str.equals(mess))
		         changed=false;
	       else{
		         mess=str;
		         changed=true;
	           }
           }

   }

具体观察者
EnemiesReceive.java

package angle_observer;


/*
     角色4.2:具体观察者:是实现观察者接口类的一个实例(包含有可以存放具体主题引用的主题接口变量)
              让具体主题引用或删除自己,使得自己成为或不再是它的观察者 
*/

import java.io.*;
import java.util.regex.*;

public class EnemiesReceive implements Observer{     //实现观察者接口的第一个类EnemiesReceive
	Subject subject;
	File myFile;
	EnemiesReceive(Subject subject,String fileName){
		this.subject=subject;
		subject.addObserver(this);    //使当前实例成为subject所引用的具体主题的观察者
		myFile=new File(fileName);
	}
	public void hearMessage(String heardMess){  //EnemiesReceive类的实例调用hearMessage(String heardMess)方法
		try{
			boolean boo=heardMess.contains("敌方");
			if(boo){
			RandomAccessFile out=new RandomAccessFile(myFile,"rw"); //若参数引用的字符串中包含有“敌方”,就将信息保存到一个文件中
			out.seek(out.length());
			byte[]b=heardMess.getBytes();
			out.write(b);
			System.out.println("-------------------------------------------");
			System.out.print("【敌方】裴擒虎"+myFile.getName());
			System.out.println("“我方防御塔被摧毁”");
			System.out.print("【敌方】不知火舞"+myFile.getName());
			System.out.println("“我方防御塔被摧毁”");
			System.out.print("【敌方】钟馗"+myFile.getName());
			System.out.println("“我方防御塔被摧毁”");
			System.out.print("【敌方】李元芳"+myFile.getName());
			System.out.println("“我方防御塔被摧毁”");
			System.out.print("【敌方】典韦"+myFile.getName());
			System.out.println("“我方防御塔被摧毁”");
		     }
		}
		catch(IOException exp){
			System.out.println(exp.toString());
		}
	}

}

TeammatesReceive.java

package angle_observer;

/*
     角色4:具体观察者:是实现观察者接口类的一个实例(包含有可以存放具体主题引用的主题接口变量)
              让具体主题引用或删除自己,使得自己成为或不再是它的观察者 
*/

import java.io.*;

public class TeammatesReceive implements Observer{   //实现观察者接口的第一个类TeammatesReceive
	Subject subject;
	File myFile;
	TeammatesReceive(Subject subject,String fileName){
		this.subject=subject;
		subject.addObserver(this);  //使当前实例成为subject所引用的具体主题的观察者
		myFile= new File(fileName);
	}
	public void hearMessage(String heardMess){    //TeammatesReceive类的实例调用hearMessage(String heardMess)方法
		try{
			RandomAccessFile out=new RandomAccessFile(myFile,"rw");  //将参数引用的字符串保存到一个文件中
			out.seek(out.length());
			byte[]b=heardMess.getBytes();
			out.write(b);              //更新文件内容
			System.out.println("【系统消息】敌方防御塔被摧毁");
			System.out.println("-------------------------------------------");
			System.out.print("【我方】娜可露露"+myFile.getName());
			System.out.println(heardMess);
			System.out.print("【我方】上官婉儿"+myFile.getName());
			System.out.println(heardMess);
			System.out.print("【我方】鬼谷子"+myFile.getName());
			System.out.println(heardMess);
			System.out.print("【我方】百里玄策"+myFile.getName());
			System.out.println(heardMess);
			System.out.print("【我方】马可波罗"+myFile.getName());
			System.out.println(heardMess);
		}
		catch(IOException exp){
			System.out.println(exp.toString());
		}
	}

}

运行结果截图

在这里插入图片描述
更多设计模式在王者荣耀中的应用请点击我的→设计模式在王者荣耀中的应用专栏

感谢阅读

END

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我了解了你的要求。下面是使用组合模式设计王者荣耀不同英雄和技能之间的组合关系的代码实现: ```python # 技能接口 class Skill: def use(self): pass # 具体技能类 class QSkill(Skill): def use(self): print("使用了Q技能") class WSkill(Skill): def use(self): print("使用了W技能") class ESkill(Skill): def use(self): print("使用了E技能") class RSkill(Skill): def use(self): print("使用了R技能") # 英雄接口 class Hero: def __init__(self): self.skills = [] def add_skill(self, skill): self.skills.append(skill) def use_skills(self): for skill in self.skills: skill.use() # 具体英雄类 class Warrior(Hero): def __init__(self): super().__init__() self.add_skill(QSkill()) self.add_skill(WSkill()) self.add_skill(ESkill()) class Mage(Hero): def __init__(self): super().__init__() self.add_skill(QSkill()) self.add_skill(WSkill()) self.add_skill(ESkill()) self.add_skill(RSkill()) # 客户端代码 if __name__ == '__main__': warrior = Warrior() mage = Mage() print("战士使用技能:") warrior.use_skills() print("\n法师使用技能:") mage.use_skills() ``` 在上面的代码,我们采用了组合模式,将英雄和技能都看作是对象,并使用组合模式来组织它们之间的关系。具体实现方式是将技能看作是叶子节点,将英雄看作是容器节点,英雄可以包含多个技能。这样,我们就可以通过英雄对象来使用它所包含的所有技能。 在代码,我们首先定义了一个技能接口和四个具体的技能类。然后定义了一个英雄接口和两个具体的英雄类。在具体的英雄类,我们通过调用 `add_skill` 方法来将各种技能添加到英雄。最后,我们在客户端代码创建了一个战士和一个法师对象,并调用它们的 `use_skills` 方法来使用它们所包含的所有技能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荣仔!最靓的仔!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值