备忘录模式(Memento模式)——游戏存进度代码实现
实现一
public class main {
public static void main(String[] args) {
GameRole gr=new GameRole();
gr.SetInitState();
gr.StateDisplay();
//保存进度
GameRole gr2=new GameRole();
gr2.setVitality(gr.getVitality());
gr2.setAttack(gr.getVitality());
gr2.setDefence(gr.getAttack());
gr.Fignt();
gr.StateDisplay();
//恢复之前的状态
gr.setAttack(gr2.getAttack());
gr.setVitality(gr2.getVitality());
gr.setDefence(gr2.getDefence());
gr.StateDisplay();
}
}
class GameRole{
int Vitality;
int Attack;
int Defence;
public int getVitality() {
return Vitality;
}
public void setVitality(int vitality) {
Vitality = vitality;
}
public int getAttack() {
return Attack;
}
public void setAttack(int attack) {
Attack = attack;
}
public int getDefence() {
return Defence;
}
public void setDefence(int defence) {
Defence = defence;
}
public void StateDisplay() {
System.out.println("角色当前状态");
System.out.println("体力:"+this.Vitality);
System.out.println("攻击力:"+this.Attack);
System.out.println("防御力:"+this.Defence);
}
public void SetInitState() {
this.Vitality=100;
this.Attack=100;
this.Defence=100;
}
public void Fignt() {
this.Vitality=0;
this.Attack=0;
this.Defence=0;
}
}
上面的代码存在的问题:
将所有的细节暴露给了客户端,导致客户端承担了太多的职责(保存状态,恢复状态,进行游戏),而且如是一旦游戏人
物的属性修改或者添加了,那么客户端相关的代码也必须修改,这些代码紧紧地耦合在了一起。
解决问题:
并不 一定需要把游戏角色这个类的所有属性都备份/存档,只需要把关心的数据进行存档,所以就要针对需妥存档的数据进行封装, 实现职责的分离。
这里,定义类RoleStateMemento封装需妥存档的数据。
实现二
public class main {
public static void main(String[] args) {
GameRole gr = new GameRole();
gr.SetInitState();
gr.StateDisplay();
// 存档
RoleStateCaretaker care = new RoleStateCaretaker();
care.setRoleStateMemento(gr.SaveRoleState());
//进行游戏
gr.Fignt();
gr.StateDisplay();
//恢复状态
gr.RecoveryState(care.getRoleStateMemento());
gr.StateDisplay();
}
}
class RoleStateMemento {
int Vitality;
int Attack;
int Defence;
public int getVitality() {
return Vitality;
}
public void setVitality(int vitality) {
Vitality = vitality;
}
public int getAttack() {
return Attack;
}
public void setAttack(int attack) {
Attack = attack;
}
public int getDefence() {
return Defence;
}
public void setDefence(int defence) {
Defence = defence;
}
public RoleStateMemento(int vitality, int attack, int defence) {
this.Vitality = vitality;
this.Attack = attack;
this.Defence = defence;
}
}
//保存memento
class RoleStateCaretaker {
RoleStateMemento roleStateMemento;
public RoleStateMemento getRoleStateMemento() {
return roleStateMemento;
}
public void setRoleStateMemento(RoleStateMemento roleStateMem) {
roleStateMemento = roleStateMem;
}
}
class GameRole {
int Vitality;
int Attack;
int Defence;
public int getVitality() {
return Vitality;
}
public void setVitality(int vitality) {
Vitality = vitality;
}
public int getAttack() {
return Attack;
}
public void setAttack(int attack) {
Attack = attack;
}
public int getDefence() {
return Defence;
}
public void setDefence(int defence) {
Defence = defence;
}
public void StateDisplay() {
System.out.println("角色当前状态");
System.out.println("体力:" + this.Vitality);
System.out.println("攻击力:" + this.Attack);
System.out.println("防御力:" + this.Defence);
}
public void SetInitState() {
this.Vitality = 100;
this.Attack = 100;
this.Defence = 100;
}
public void Fignt() {
this.Vitality = 0;
this.Attack = 0;
this.Defence = 0;
}
// 存档状态
public RoleStateMemento SaveRoleState() {
return new RoleStateMemento(this.Vitality, this.Attack, this.Defence);
}
// 从RoleStateMemento恢复状态
public void RecoveryState(RoleStateMemento memento) {
this.Vitality = memento.Vitality;
this.Attack = memento.Attack;
this.Defence = memento.Defence;
}
}
在进行软件系统设计的时候给用户后悔的权利(实际上可能也是用户妥求的权利),
对一些关键性的操作需要提供诸如撤销(Undo)的操作。这种操作就是Memento模式提供的。
Memento模式: 在不破坏封装性的前提 捕获一个对象的内部状态, 并在该对象之外保存这个状态。这样以
后就可以利用该保存的状态实施恢复操作。
Memento模式的共型结构图为:
Memento(备忘录): 负责存储Originator 对象的内部状态, 并可以防止Originator以外的其他对象访问 备忘录。
备忘录有两个接口:
Caretaker只能看到备忘录的 宿报 它只能将各忘录传递给其它对象。
Originator可看到备忘录的宽接 它可以访问返回到先前状态所需要的所有数据。
Memento模式基本代码
public class main {
public static void main(String[] args) {
Originator o=new Originator();
o.setState("On");
o.Show();
Caretaker c=new Caretaker();
c.setMemento(o.CreateMemento());
o.setState("Off");
o.Show();
//恢复初始状态
o.SetMemento(c.getMemento());
o.Show();
}
}
class Originator{
private String state;//需要保存的属性,可能有多个
public String getState() {
return state;
}
public void setState(String state) {
this.state=state;
}
public Memento CreateMemento() {
//创建备忘录,将当前需要保存的信息导入并实例化一个Memento对象
return(new Memento(state));
}
public void SetMemento(Memento memento) {
//恢复备忘录,将memento导并将相关数据恢复
state=memento.getState();
}
public void Show() {
//显示数据
System.out.println("State="+state);
}
}
//备忘录类
class Memento{
private String state;
public Memento(String state) {
this.state=state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
备忘录模式和原型模式这两个模式可以结合使用
在发起人对象创建各忘录对象的时候, 如发起人对象中全部或者大部分的状态都需要保存,一个简洁的方式就是直接克隆 一个发起人对象。
也就是说,这个时候备忘录对象里面存放的是一个发起人对象的实例。
数据结构模式
常常有一些组件在内部其有特定的数据结构,如是让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。
这时候, 将这些特定数据结构封装在内部,在外部提供统一的接口, 来实现与特定数据结构无关的访问,是种行之有效的解决方案。
典型模式:
Composite
Iterator
Chain of Resposibility
组合模式
在软件在某些情况下,客户代码过多地位赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客广代码的频繁文化,带来了代码的
维护性、扩展性等弊端。如何将 “客户代码与复杂的对象容器结构"解耦?让对象容器自己未实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
不带模式的解决方案:组合模式
public class main {
public static void main(String[] args) {
Composite root = new Composite("服装");
Composite c1 = new Composite("男装");
Composite c2 = new Composite("女装");
//定义所有叶子节点
Leaf l1=new Leaf("衬衣");
Leaf l2=new Leaf("夹克");
Leaf l3=new Leaf("裙子");
Leaf l4=new Leaf("套装");
root.addComposite(c1);
root.addComposite(c2);
c1.addLeaf(l1);
c1.addLeaf(l2);
c2.addLeaf(l3);
c2.addLeaf(l4);
root.printStruct(0);
}
}
class Leaf {
private String name = "";
public Leaf(String name) {
this.name = name;
}
public void printStruct(int d) {
for (int i = 0; i < d; i++) {
System.out.println("-" + name);
}
}
}
class Composite {
private Collection<Composite> childComposite = new ArrayList<Composite>();
private Collection<Leaf> childLeaf = new ArrayList<Leaf>();
private String name = "";
public Composite(String name) {
this.name = name;
}
public void addComposite(Composite c) {
this.childComposite.add(c);
}
public void addLeaf(Leaf leaf) {
this.childLeaf.add(leaf);
}
public void printStruct(int d) {
for (int i=0; i < d; i++) {
System.out.println(" ");
}
System.out.println("+"+name);
for (Leaf leaf : childLeaf) {
leaf.printStruct(d + 2);
}
for (Composite c : childComposite) {
c.printStruct(d + 2);
}
}
}
改进:
要处理的对象可以表示成 个树形结构,而要对树上的分支节点和叶子进行操作时,它能够提供一致的方式,而不用区
分它是分支节点还是叶子—— 抽象出共同基类Component继承它产生计子节点和空
public class main {
public static void main(String[] args) {
Composite root = new Composite("服装");
Composite c1 = new Composite("男装");
Composite c2 = new Composite("女装");
//定义所有叶子节点
Leaf l1=new Leaf("衬衣");
Leaf l2=new Leaf("夹克");
Leaf l3=new Leaf("裙子");
Leaf l4=new Leaf("套装");
root.Add(c1);
root.Add(c2);
c1.Add(l1);
c1.Add(l2);
c2.Add(l3);
c2.Add(l4);
root.printStruct(0);
}
}
abstract class Component{
protected String name;
public Component(String name) {
this.name=name;
}
public abstract void Add(Component component);
public abstract void Remove(Component component);
public abstract void printStruct(int component);
}
class Leaf extends Component{
public Leaf(String name) {
super(name);
}
public void Add(Component component) {
System.out.println("不能添加分支");
}
public void printStruct(int d) {
for(int i=0;i<d;i++) {
System.out.println(" ");
}
System.out.println("-"+name);
}
public void Remove(Component component) {
System.out.println("不能删除分支");
}
}
class Composite extends Component{
private ArrayList<Component>components=new ArrayList<Component>();
public Composite(String name) {
super(name);
}
@Override
public void Add(Component component) {
components.add(component);
}
@Override
public void Remove(Component component) {
components.remove(component);
}
@Override
public void printStruct(int d) {
for (int i=0; i < d; i++) {
System.out.println(" ");
}
System.out.println("+"+name);
for (Component c : components) {
c.printStruct(d+2);
}
}
}
组合模式代码
public class main {
public static void main(String[] args) {
//生成树根,根上长出两个树叶
Composite c=new Composite("ROOT");
c.Add(new Leaf("leafA"));
c.Add(new Leaf("leafB"));
//根上长出分支CompositeX.分支上也有两叶LeafA和LeafB
Composite c1=new Composite("CompositeX");
c1.Add(new Leaf("LeafAx"));
c1.Add(new Leaf("LeafBx"));
c.Add(c1);
Composite c2=new Composite("compositeXY");
c2.Add(new Leaf("LeafAxy"));
c2.Add(new Leaf("LeafBxy"));
c1.Add(c2);
c.Add(new Leaf("leafaxyc"));
Leaf leaf=new Leaf("Leafaxyd");
c.Add(leaf);
c.Remove(leaf);
c.Display(1);
}
}
//Component为组合中的对象声明接口
abstract class Component{
protected String name;
public Component(String name) {
this.name=name;
}
public abstract void Add(Component component);
public abstract void Remove(Component component);
public abstract void Display(int component);
}
class Leaf extends Component{
public Leaf(String name) {
super(name);
}
public void Add(Component component) {
System.out.println("不能添加一个树叶");
}
public void Remove(Component component) {
System.out.println("不能删除一个叶子");
}
public void Display(int d) {
for(int i=0;i<d;i++) {
System.out.println(" ");
}
System.out.println("-"+name);
}
}
//定义有枝节点行为,用来储存子部件在Component接口中实现与子部件有关的操作,比如Add和Remove
class Composite extends Component{
private ArrayList<Component>components=new ArrayList<Component>();
public Composite(String name) {
super(name);
}
public void Add(Component component) {
components.add(component);
}
public void Remove(Component component) {
components.remove(component);
}
public void Display(int d) {
for (int i=0; i < d; i++) {
System.out.println(" ");
}
System.out.println("+"+name);
for (Component c : components) {
c.Display(d+2);
}
}
}