zl程序教程

您现在的位置是:首页 >  后端

当前栏目

从王者荣耀看设计模式(二十二.备忘录模式)

模式设计模式 荣耀 备忘录 王者 二十二
2023-09-11 14:21:44 时间

从王者荣耀看设计模式

一.简介

点击王者荣耀商店法术的装备栏,存在有"贤者的庇护"这一装备。在对战中,当玩家处于死亡状态时,会触发此装备的效果,能够让英雄重新复活。
┬┴┬┌─ ●─┬─  │─┼─┐ ●├─┤○
┴┬┴├┬ ┌─┼─ │◎ │ │ ○└┬┘●
─┼─││ │ │  ││─┴─┴ ──┼──
●│○││ ┴─┼─  │○  ● / │ \

二.模式动机

在应用软件的开发中,很多时候我们都需要记录一个对象的内部状态。在具体实现时,为了允许用户取消不确定的操作或从错误中恢复过来,需要设置备份点并提供撤销机制,而要实现这些机制,必须事先将状态信息保存在某处,这样才能将对象恢复到它们原先的状态。备忘录模式是一种给我们的软件提供后悔药的机制,通过它可以使系统恢复到某一特定的历史状态。在本实例中,装备提供备份的功能,将英雄死亡之前的状态备份,英雄死亡触发备份事件将备份状态取出

三.备忘录模式

备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是种对象行为型模式

备忘录模式的应用场景
在以下情况下可以使用备忘录模式
■ 保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态
■ 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过负责人可以间接访问其内部状态

备忘录模式的通用类图

备忘录模式涉及的角色
备忘录模式包含以下角色
⑴.Originator(原发器):原发器可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般需要保存内部状态的类设计为原发器,如一个存储用户信息或商品信息的对象
⑵.Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参照原发器的设计,根据实际需要来确定备忘录中的属性,需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用
⑶. Caretaker(负责人)
负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查,在负责人对象中可以存储一个或多个对象,它只负责存储对象,而不能修改对象,也无法知道对象的具体实现细节

备忘录模式优点:
⑴.提供一种状态恢复的实现机制
⑵.实现了信息的封装,使用堆栈来存储备忘录对象可以实现多次撤销操作

备忘录模式缺点:
资源消耗大,每保存一次状态都要耗费内存资源

四.结构图

五.代码实现

Originator类

package com.practice.memento;
/*
 * 创建原发器类,存储当前的内部状态
 */
public class Originator {
	private String state;
	
	public void setState(String state) {
		this.state = state;
	}
	
	public String getState() {
		return state;
	}
	//创建备忘录,存储当前状态
	public Memento createMemento() {
		return new Memento(state);
	}
	//将存储的状态从备忘录中取出
	public void restoreMemento(Memento m) {
		this.setState(m.getState());
	}
}

Memento类

package com.practice.memento;
/*
 * 创建备忘录类,存储原发器的内部状态
 */
public class Memento {
	private String state;
	//接收原发器的内部状态
	public Memento(String state) {
		this.state = state;
	}
	
	public void setState(String state) {
		this.state = state;
	}
	
	public String getState() {
		return state;
	}
}

Caretaker类

package com.practice.memento;
/*
 * 创建负责人类,负责保存备忘录,存储备忘录对象
 */
public class Caretaker {
	private Memento memento;
	
	public void setMemento(Memento m) {
		memento = m;
	}
	
	public Memento getMemento() {
		return memento;
	}
}

Client类

package com.practice.memento;

public class Client {
	public static void main(String[] args) {
		//创建原发器对象
		Originator or = new Originator();
		//创建负责人对象
		Caretaker cr = new Caretaker();
		//设置原发器当前状态
		or.setState("You are still alive!");
		System.out.println("初始状态:" + or.getState());
		//将原发器当前状态存入备忘录中
		cr.setMemento(or.createMemento());
		//设置原发器新状态
		or.setState("You have been slained!");
		System.out.println("新的状态" + or.getState());
		//将初始状态从备忘录中取出
		or.restoreMemento(cr.getMemento());
		System.out.println("恢复状态:" + or.getState());
	}
}

运行结果:

六.备忘录模式的应用

实例说明
利用栈来存储备忘录对象是一种常见的行为,在本实例中,在GUI界面中一共有四位英雄可以供玩家选择,玩家选择完后按确定键确定选择,按返回键返回上次选择状态。
结构类图

代码实现
Client类

package com.practice.memento;

public class Client {
	public static void main(String[] args) {
		new HeroGame();
	}
}

HeroGame类

package com.practice.memento;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

public class HeroGame extends JFrame implements ActionListener{
	/**
	 * 客户类
	 */
	private static final long serialVersionUID = 1L;
	JPanel CenterJP, EastJP;
	JRadioButton hero1, hero2, hero3, hero4;
	JButton button1, button2;
	String FileName;
	JLabel g;
	PlayerOriginator po;
	HeroStack hs;

	public HeroGame() {
		super("王者荣耀与备忘录模式");
		po = new PlayerOriginator();
		hs = new HeroStack();
		this.setBounds(0,0,900,380);
		this.setResizable(false);
		FileName = "src/com/practice/photo/hero.jpg";
		g = new JLabel(new ImageIcon(FileName),JLabel.CENTER);
		CenterJP = new JPanel();
		CenterJP.setLayout(new GridLayout(1,4));
		CenterJP.setBorder(BorderFactory.createTitledBorder("英雄如下:"));
		CenterJP.add(g);
		this.add("Center",CenterJP);
		EastJP = new JPanel();
		EastJP.setLayout(new GridLayout(1,1));
		EastJP.setBorder(BorderFactory.createTitledBorder("您选择的英雄是:"));
		this.add("East",EastJP);
		JPanel SouthJP = new JPanel();
		JLabel info = new JLabel("您要选择四位英雄中的哪一位?");
		hero1 = new JRadioButton("伽罗",true);
		hero2 = new JRadioButton("小乔");
		hero3 = new JRadioButton("大乔");
		hero4 = new JRadioButton("娜可露露");
		button1 = new JButton("确定");
		button2 = new JButton("返回");
		ButtonGroup group = new ButtonGroup();
		group.add(hero1);
		group.add(hero2);
		group.add(hero3);
		group.add(hero4);
		SouthJP.add(info);
		SouthJP.add(hero1);
		SouthJP.add(hero2);
		SouthJP.add(hero3);
		SouthJP.add(hero4);
		SouthJP.add(button1);
		SouthJP.add(button2);
		button1.addActionListener(this);
		button2.addActionListener(this);
		this.add("South",SouthJP);
		showPicture("空白");
		po.setHero("空白");
		hs.push(po.createMemento());
	}
	
	//显示图片
	void showPicture(String name) {
		EastJP.removeAll();
		EastJP.repaint();
		po.setHero(name);
		FileName = "src/com/practice/photo/" + name + ".png";
		g = new JLabel(new ImageIcon(FileName),JLabel.CENTER);
		EastJP.add(g);
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		boolean ok = false;
		if(e.getSource() == button1) {
			ok = hs.push(po.createMemento());//保存状态
			if(ok && hero1.isSelected()) {
				showPicture("伽罗");
			}else if(ok && hero2.isSelected()) {
				showPicture("小乔");
			}else if(ok && hero3.isSelected()) {
				showPicture("大乔");
			}else if(ok && hero4.isSelected()) {
				showPicture("娜可露露");
			}
		}else if(e.getSource() == button2) {
			po.restoreMemento(hs.pop());//恢复状态
			showPicture(po.getHero());
		}
	}
}

PlayerOriginator类

package com.practice.memento;
/*
 * 发起类
 */
public class PlayerOriginator {
	private String heroName;
	
	public void setHero(String heroName) {
		this.heroName = heroName;
	}
	
	public String getHero() {
		return heroName;
	}
	
	public Hero createMemento() {
		return new Hero(heroName);
	}
	
	public void restoreMemento(Hero p) {
		setHero(p.getHero());
	}
}

Hero类

package com.practice.memento;
/*
 * 备忘录类
 */
public class Hero {
	private String name;
	
	public Hero(String name) {
		this.name = name;
	}
	
	public void setHero(String name) {
		this.name = name;
	}
	
	public String getHero() {
		return name;
	}
}

HeroStack类

package com.practice.memento;
/*
 * 管理者类
 */
public class HeroStack {
	private Hero hero[];
	private int top;
	
	public HeroStack() {
		hero = new Hero[10];
		top = -1;
	}
	
	public boolean push(Hero p) {
		if(top >= 10) {
			System.out.println("放过小老弟,记不住了");
			return false;
		}else {
			hero[++top] = p;
			return true;
		}
	}
	
	public Hero pop() {
		if(top <= 0) {
			System.out.println("英雄栈空了!");
			return hero[0];
		}else
			return hero[top--];
	}
}

运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fux8yH2H-1611481205135)(https://img2018.cnblogs.com/blog/1597476/202001/1597476-20200120192649616-2048426763.gif)]

七.源代码下载

从王者荣耀看设计模式(备忘录模式)