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


    从王者荣耀看设计模式

    一.简介

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

    二.模式动机

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

    三.备忘录模式

    备忘录模式(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--];
    	}
    }
    

    运行结果:

    七.源代码下载

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

  • 相关阅读:
    求长度的另一种方法(""+obj).Length
    XCode中如何使用事务
    最终版 Reflector v1.0 (+简单的反流程混淆)
    与ObjectDataSource共舞
    性能&分布式&NewLife.XCode对无限数据的支持
    XCode之第一次亲密接触
    5,ORM组件XCode(动手)
    你知道吗?多个类多线程环境下静态构造函数的执行顺序
    使用C#编写IDA插件 IDACSharp v1.0.2010.0605
    XCMS V1.0 Beta1 发布
  • 原文地址:https://www.cnblogs.com/miaowulj/p/12217485.html
Copyright © 2020-2023  润新知