万字解析设计模式之迭代器模式、备忘录模式

一、迭代器模式

1.1概述

迭代器模式是一种行为型设计模式,它允许在没有暴露其底层表现形式的情况下遍历集合对象。迭代器模式提供一种通用的遍历机制,可以遍历任何类型的集合,包括数组、列表、树等。通过这种模式,可以实现一种通用的遍历接口,从而减少了代码重复性,提高了代码的可复用性。

1.2结构

 迭代器模式主要包含以下角色:

  • 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。
  • 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
  • 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 等方法。可以包含一个工厂方法用于生成具体迭代器。
  • 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

1.3实现

 【例】定义一个可以存储学生对象的容器对象,将遍历该容器的功能交由迭代器实现,涉及到的类如下:

 

package com.yanyu.Iterator;

public class Student {
    private String name;

    private String number;

    public Student(String name, String number) {
        this.name = name;
        this.number = number;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", number='" + number + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }


}

抽象迭代器(Iterator)角色

package com.yanyu.Iterator;

public interface StudentIterator {
    boolean hasNext();
    Student next();
}

具体迭代器(Concretelterator)角色

package com.yanyu.Iterator;


import java.util.List;

public class StudentIteratorImpl implements StudentIterator {
    private List<Student> list;
    private int position = 0;

    public StudentIteratorImpl(List<Student> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        return position < list.size();
    }

    @Override
    public Student next() {
        Student currentStudent = list.get(position);
        position ++;
        return currentStudent;
    }
}

 抽象聚合(Aggregate)角色

package com.yanyu.Iterator;


public interface StudentAggregate {
    void addStudent(Student student);

    void removeStudent(Student student);

    StudentIterator getStudentIterator();
}

具体聚合(ConcreteAggregate)角色

package com.yanyu.Iterator;

import java.util.ArrayList;
import java.util.List;

public class StudentAggregateImpl implements StudentAggregate {

    private List<Student> list = new ArrayList<Student>();  // 学生列表

    @Override
    public void addStudent(Student student) {
        this.list.add(student);
    }

    @Override
    public void removeStudent(Student student) {
        this.list.remove(student);
    }

    @Override
    public StudentIterator getStudentIterator() {
        return new StudentIteratorImpl(list);
    }
}

客户端类

package com.yanyu.Iterator;

public class Client {
    public static void main(String[] args) {
        // 创建聚合对象
        StudentAggregateImpl aggregate = new StudentAggregateImpl();
        // 添加元素
        aggregate.addStudent(new Student("张三", "001"));
        aggregate.addStudent(new Student("李四", "002"));
        aggregate.addStudent(new Student("王五", "003"));
        aggregate.addStudent(new Student("赵六", "004"));

        // 遍历聚合对象
        // 1. 获取迭代器对象
        StudentIterator iterator = aggregate.getStudentIterator();
        // 2. 遍历
        while(iterator.hasNext()) {
            // 3. 获取元素
            Student student = iterator.next();
            System.out.println(student.toString());
        }
    }
}

1.4优缺点

1,优点:

  • 它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持新的遍历方式。
  • 迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样可以简化聚合类的设计。
  • 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足 “开闭原则” 的要求。

2,缺点:

增加了类的个数,这在一定程度上增加了系统的复杂性。

1.5应用场景 

适应的场景:

  1. 当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。迭代器封装了与复杂数据结构进行交互的细节, 为客户端提供多个访问集合元素的简单方法。 这种方式不仅对客户端来说非常方便, 而且能避免客户端在直接与集合交互时执行错误或有害的操作, 从而起到保护集合的作用。

  2. 使用该模式可以减少程序中重复的遍历代码。重要迭代算法的代码往往体积非常庞大。 当这些代码被放置在程序业务逻辑中时, 它会让原始代码的职责模糊不清, 降低其可维护性。 因此, 将遍历代码移到特定的迭代器中可使程序代码更加精炼和简洁。 

二、备忘录模式

2.1概述

又叫快照模式,在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,很多软件都提供了撤销(Undo)操作,如 Word、记事本、Photoshop、IDEA等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;还有在 浏览器 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。

2.2结构

备忘录模式的主要角色如下:

  • 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  • 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

备忘录有两个等效的接口:

  • 窄接口:管理者(Caretaker)对象(和其他发起人对象之外的任何对象)看到的是备忘录的窄接口(narror Interface),这个窄接口只允许他把备忘录对象传给其他的对象。
  • 宽接口:与管理者看到的窄接口相反,发起人对象可以看到一个宽接口(wide Interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。

2.3实现

【例】游戏挑战BOSS

游戏中的某个场景,一游戏角色有生命力、攻击力、防御力等数据,在打Boss前和后一定会不一样的,我们允许玩家如果感觉与Boss决斗的效果不理想可以让游戏恢复到决斗之前的状态。

要实现上述案例,有两种方式:

  • “白箱”备忘录模式
  • “黑箱”备忘录模式

“白箱”备忘录模式

备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。类图如下

 发起人


package com.yanyu.memory.whitebox;

//游戏角色类
public class GameRole {
    private int vit; //生命力
    private int atk; //攻击力
    private int def; //防御力

    //初始化状态
    public void initState() {
        this.vit = 100; // 初始化生命力为100
        this.atk = 100; // 初始化攻击力为100
        this.def = 100; // 初始化防御力为100
    }

    //战斗
    public void fight() {
        this.vit = 0; // 生命力归零
        this.atk = 0; // 攻击力归零
        this.def = 0; // 防御力归零
    }

    //保存角色状态
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit, atk, def); // 创建并返回包含当前状态的备忘录对象
    }

    //回复角色状态
    public void recoverState(RoleStateMemento roleStateMemento) {
        this.vit = roleStateMemento.getVit(); // 恢复生命力
        this.atk = roleStateMemento.getAtk(); // 恢复攻击力
        this.def = roleStateMemento.getDef(); // 恢复防御力
    }

    public void stateDisplay() {
        System.out.println("角色生命力:" + vit); // 显示生命力
        System.out.println("角色攻击力:" + atk); // 显示攻击力
        System.out.println("角色防御力:" + def); // 显示防御力
    }

    public int getVit() {
        return vit; // 返回生命力
    }

    public void setVit(int vit) {
        this.vit = vit; // 设置生命力
    }

    public int getAtk() {
        return atk; // 返回攻击力
    }

    public void setAtk(int atk) {
        this.atk = atk; // 设置攻击力
    }

    public int getDef() {
        return def; // 返回防御力
    }

    public void setDef(int def) {
        this.def = def; // 设置防御力
    }
}

备忘录(Memento)角色

package com.yanyu.memory.whitebox;


//游戏状态存储类(备忘录类)
public class RoleStateMemento {
    private int vit; // 生命力
    private int atk; // 攻击力
    private int def; // 防御力

    // 构造函数,传入生命力、攻击力、防御力进行初始化
    public RoleStateMemento(int vit, int atk, int def) {
        this.vit = vit; // 初始化生命力
        this.atk = atk; // 初始化攻击力
        this.def = def; // 初始化防御力
    }

    // 获取生命力
    public int getVit() {
        return vit; // 返回生命力
    }

    // 设置生命力
    public void setVit(int vit) {
        this.vit = vit; // 设置生命力
    }

    // 获取攻击力
    public int getAtk() {
        return atk; // 返回攻击力
    }

    // 设置攻击力
    public void setAtk(int atk) {
        this.atk = atk; // 设置攻击力
    }

    // 获取防御力
    public int getDef() {
        return def; // 返回防御力
    }

    // 设置防御力
    public void setDef(int def) {
        this.def = def; // 设置防御力
    }
}

管理者(Caretaker)角色

package com.yanyu.memory.whitebox;

//角色状态管理者类
public class RoleStateCaretaker {
    private RoleStateMemento roleStateMemento; // 保存角色状态的备忘录对象

    // 获取角色状态的备忘录对象
    public RoleStateMemento getRoleStateMemento() {
        return roleStateMemento; // 返回角色状态的备忘录对象
    }

    // 设置角色状态的备忘录对象
    public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
        this.roleStateMemento = roleStateMemento; // 设置角色状态的备忘录对象
    }
}

客户端类

package com.yanyu.memory.whitebox;



//测试类
public class Client {
    public static void main(String[] args) {
        System.out.println("------------大战Boss前------------");
        //大战Boss前
        GameRole gameRole = new GameRole(); // 创建游戏角色对象
        gameRole.initState(); // 初始化角色状态
        gameRole.stateDisplay(); // 显示角色状态

        //保存进度
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); // 创建角色状态管理者对象
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState()); // 保存当前角色状态到备忘录对象

        System.out.println("------------大战Boss后------------");
        //大战Boss时,损耗严重
        gameRole.fight(); // 模拟角色大战Boss,损耗状态
        gameRole.stateDisplay(); // 显示角色损耗后的状态
        System.out.println("------------恢复之前状态------------");
        //恢复之前状态
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento()); // 恢复之前保存的角色状态
        gameRole.stateDisplay(); // 显示恢复后的角色状态
    }
}

适合应用场景

  • 如果你需要对一个复杂对象结构 (例如对象树) 中的所有元素执行某些操作, 可使用访问者模式。

访问者模式通过在访问者对象中为多个目标类提供相同操作的变体, 让你能在属于不同类的一组对象上执行同一操作。

  • 可使用访问者模式来清理辅助行为的业务逻辑。

该模式会将所有非主要的行为抽取到一组访问者类中, 使得程序的主要类能更专注于主要的工作。

  • 当某个行为仅在类层次结构中的一些类中有意义, 而在其他类中没有意义时, 可使用该模式。

你可将该行为抽取到单独的访问者类中, 只需实现接收相关类的对象作为参数的访问者方法并将其他方法留空即可。

“黑箱”备忘录模式

备忘录角色对发起人对象提供一个宽接口,而为其他对象提供一个窄接口。在Java语言中,实现双重接口的办法就是将备忘录类设计成发起人类的内部成员类。

将 RoleStateMemento 设为 GameRole 的内部类,从而将 RoleStateMemento 对象封装在 GameRole 里面;在外面提供一个标识接口 Memento 给 RoleStateCaretaker 及其他对象使用。这样 GameRole 类看到的是 RoleStateMemento 所有的接口,而RoleStateCaretaker 及其他对象看到的仅仅是标识接口 Memento 所暴露出来的接口,从而维护了封装型。类图如下:

窄接口 

package com.yanyu.memory.blackbox;

public interface Memento {
}

 发起人

package com.yanyu.memory.blackbox;


// 游戏角色类
public class GameRole {
    private int vit; // 生命力
    private int atk; // 攻击力
    private int def; // 防御力

    // 初始化状态
    public void initState() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }

    // 战斗
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }

    // 保存角色状态
    public Memento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }

    // 回复角色状态
    public void recoverState(Memento memento) {
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }

    public void stateDisplay() {
        System.out.println("角色生命力:" + vit);
        System.out.println("角色攻击力:" + atk);
        System.out.println("角色防御力:" + def);
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    // 角色状态备忘录类
    private class RoleStateMemento implements Memento {
        private int vit;
        private int atk;
        private int def;

        public RoleStateMemento(int vit, int atk, int def) {
            this.vit = vit;
            this.atk = atk;
            this.def = def;
        }

        public int getVit() {
            return vit;
        }

        public void setVit(int vit) {
            this.vit = vit;
        }

        public int getAtk() {
            return atk;
        }

        public void setAtk(int atk) {
            this.atk = atk;
        }

        public int getDef() {
            return def;
        }

        public void setDef(int def) {
            this.def = def;
        }
    }
}

管理者角色

package com.yanyu.memory.blackbox;


//角色状态管理者类
public class RoleStateCaretaker {
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

 客户端类

package com.yanyu.memory.blackbox;

public class Client {
    public static void main(String[] args) {
        System.out.println("------------大战Boss前------------");
        //大战Boss前
        GameRole gameRole = new GameRole();
        gameRole.initState();
        gameRole.stateDisplay();
        //保存进度
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
        roleStateCaretaker.setMemento(gameRole.saveState());

        System.out.println("------------大战Boss后------------");
        //大战Boss时,损耗严重
        gameRole.fight();
        gameRole.stateDisplay();
        System.out.println("------------恢复之前状态------------");
        //恢复之前状态
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.stateDisplay();
    }
}

三、迭代器模式实验

任务描述

假设需要开发一个社交电商网站,在对该系统进行分析和设计时,开发人员发现经常需要对系统中的热门商品、热门博主等数据等进行遍历,为了复用这些遍历代码,开发人员设计了一个抽象的数据集合类 AbstractObjectListAbstractObjectList 类的子类 ProductList 用于存储热门商品数据。

本关任务:请用迭代器模式实现一个遍历热门商品的功能。熟悉自定义迭代器和语言自带迭代器的用法与区别。

实现方式

  1. 声明迭代器接口。 该接口必须提供至少一个方法来获取集合中的下个元素。 但为了使用方便, 你还可以添加一些其他方法, 例如获取前一个元素、 记录当前位置和判断迭代是否已结束;

  2. 声明集合接口并描述一个获取迭代器的方法。 其返回值必须是迭代器接口。 如果你计划拥有多组不同的迭代器, 则可以声明多个类似的方法;

  3. 为希望使用迭代器进行遍历的集合实现具体迭代器类。 迭代器对象必须与单个集合实体链接。 链接关系通常通过迭代器的构造函数建立;

  4. 在你的集合类中实现集合接口。 其主要思想是针对特定集合为客户端代码提供创建迭代器的快捷方式。 集合对象必须将自身传递给迭代器的构造函数来创建两者之间的链接;

  5. 检查客户端代码, 使用迭代器替代所有集合遍历代码。 每当客户端需要遍历集合元素时都会获取一个新的迭代器。

编程要求

根据提示,在右侧编辑器 Begin-End 内补充 “Client.java”中的代码,其它文件的代码不需要改变。

测试说明

输入热门商品数量和商品名称,平台会对你编写的代码进行测试:

测试输入: 4 拖把 橘子 剃须刀 面膜 预期输出: 拖把 橘子 剃须刀 面膜 -------------------- 面膜 剃须刀 橘子 拖把

抽象迭代器

package step1;
//抽象迭代器
public interface AbstractInterator{
     void next();    //移至下一个元素
     boolean isLast();   //判断是否为最后一个元素
     void previous();   //移至上一个元素
     boolean isFirst();  //判断是否为第一个元素
     Object getNextItem();  //获取下一个元素
     Object getPreviousItem();   //获取上一个元素
}

具体迭代器

package step1;

import java.util.List;

// 抽象迭代器容器
public abstract class AbstractObjectList {
    // 定义对象列表
    protected List<Object> objects;

    // 构造方法,接收一个对象列表
    public AbstractObjectList(List objects) {
        this.objects = objects;
    }

    // 添加对象到列表
    public void addObject(Object obj) {
        this.objects.add(obj);
    }

    // 从列表中移除对象
    public void removeObject(Object obj) {
        this.objects.remove(obj);
    }

    // 获取对象列表
    public List getObjects() {
        return this.objects;
    }

    // 声明创建迭代器对象的抽象工厂方法
    public abstract AbstractInterator createIterator();
}

 抽象聚合(Aggregate)角色

package step1;

import java.util.List;
//具体商品的容器
public class ProductList extends AbstractObjectList{
    public ProductList(List products) {

        super(products);
    }

    //实现创建迭代器对象的具体方法
    @Override
    public AbstractInterator createIterator() {

        return new ProductIterator(this);
    }
}

具体聚和角色

package step1;

import java.util.List;

// 具体商品的迭代器
public class ProductIterator implements AbstractInterator {
    private List products;  // 商品列表
    private int cursor1;     // 定义一个游标,用于记录正向遍历的位置
    private int cursor2;     // 定义一个游标,用于记录逆向遍历的位置

    // 构造方法,接收一个商品列表
    public ProductIterator(ProductList list) {
        this.products = list.getObjects();  // 获取集合对象
        cursor1 = 0;    // 设置正向遍历游标的初始值
        cursor2 = products.size() - 1;  // 设置逆向遍历游标的初始值
    }

    @Override
    public void next() {
        if (cursor1 < products.size()) {
            cursor1++;
        }
    }

    @Override
    public boolean isLast() {
        return (cursor1 == products.size());
    }

    @Override
    public void previous() {
        if (cursor2 > -1) {
            cursor2--;
        }
    }

    @Override
    public boolean isFirst() {
        return (cursor2 == -1);
    }

    @Override
    public Object getNextItem() {
        return products.get(cursor1);
    }

    @Override
    public Object getPreviousItem() {
        return products.get(cursor2);
    }
}

 客户端类

package step1;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        List products = new ArrayList<String>();
        Scanner scanner = new Scanner(System.in);
        int nums = scanner.nextInt();
        for (int i = 0; i < nums; i++) {
            products.add(scanner.next());
        }
        /********** Begin *********/
        ///请用java自带的iterator实现products的正向遍历访问

       Iterator<String> iterator = products.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }


        /********** End *********/
        System.out.println("--------------------");

        /********** Begin *********/
        ///请用自定义的iterator实现products的反向遍历访问
         AbstractInterator iterator1 = new ProductIterator(new ProductList(products));
        while (!iterator1.isFirst()) {
            System.out.println(iterator1.getPreviousItem());
            iterator1.previous();
        }



        /********** End *********/
    }
}

四、备忘录模式实验

任务描述

在计算机专业的实践教学系统中,学生需要根据教师提供的模板框架来补充、改写程序。学生在编写代码过程中可能会因为思路不清晰而导致框架原有结构被破坏,因此学生希望系统具有恢复成初始状态的功能,这样就能重新开始。

本关任务:请用备忘录模式来实现模板框架的恢复功能。

实现方式

  1. 确定担任原发器角色的类。 重要的是明确程序使用的一个原发器中心对象, 还是多个较小的对象;

  2. 创建备忘录类。 逐一声明对应每个原发器成员变量的备忘录成员变量;

  3. 将备忘录类设为不可变。 备忘录只能通过构造函数一次性接收数据。 该类中不能包含设置器;

  4. 如果你所使用的编程语言支持嵌套类, 则可将备忘录嵌套在原发器中; 如果不支持, 那么你可从备忘录类中抽取一个空接口, 然后让其他所有对象通过接口来引用备忘录。 你可在该接口中添加一些元数据操作, 但不能暴露原发器的状态;

  5. 在原发器中添加一个创建备忘录的方法。 原发器必须通过备忘录构造函数的一个或多个实际参数来将自身状态传递给备忘录。该方法返回结果的类型必须是你在上一步中抽取的接口 (如果你已经抽取了)。 实际上, 创建备忘录的方法必须直接与备忘录类进行交互;

  6. 在原发器类中添加一个用于恢复自身状态的方法。 该方法接受备忘录对象作为参数。 如果你在之前的步骤中抽取了接口, 那么可将接口作为参数的类型。 在这种情况下, 你需要将输入对象强制转换为备忘录, 因为原发器需要拥有对该对象的完全访问权限;

  7. 无论负责人是命令对象、 历史记录或其他完全不同的东西, 它都必须要知道何时向原发器请求新的备忘录、 如何存储备忘录以及何时使用特定备忘录来对原发器进行恢复;

  8. 负责人与原发器之间的连接可以移动到备忘录类中。 在本例中, 每个备忘录都必须与创建自己的原发器相连接。 恢复方法也可以移动到备忘录类中, 但只有当备忘录类嵌套在原发器中, 或者原发器类提供了足够多的设置器并可对其状态进行重写时, 这种方式才能实现。

编程要求

根据提示,在右侧编辑器补充 Originator.java 文件中 Begin-End 内的代码,其它文件不需要修改。

测试说明

测试流程思想:先打印出内置的模板,然后读取你的输入替换模板再打印出来,最后把恢复后的代码再次打印出来:

测试输入: this is my code

预期输出: this is ______code this is my code this is ______code

窄接口

package step1;

public interface Memento {
}

 发起人(Originator)角色

package step1;

public class Originator {
    private  String mould;

    public void  ReadMould()
    {
        //假设从数据库中读取模板代码
        this.mould = "this is ______code";
    }
    ///setMould是学生修改以后提交的代码
    public void setMould( String code)
    {
        this.mould= code;
    }
    public String getMould()
    {
        return mould;
    }
    private static class MementoImpl implements Memento
    {
        /********** Begin *********/
        private String mould;
        public MementoImpl(String mould) {
            this.mould = mould;
        }

        public String getMould(){
            return mould;
        }

        public void setMemento(String mould) {
            this.mould = mould;
        }

       
        /********** End *********/
    }
    public Memento createMemento() {
        /********** Begin *********/
         return new MementoImpl(mould);
        /********** End *********/
    }
    public void restoreMemento(Memento memento)
    {
        /********** Begin *********/
        MementoImpl roleStateMemento = (MementoImpl) memento;
        this.mould = roleStateMemento.getMould();
        /********** End *********/
    }
}

管理者角色 

package step1;

public class Caretaker {
    private Memento memento = null;

    public void setMemento(Memento memento){
        this.memento = memento;
    }
    public Memento getMemento(){
        return this.memento;
    }

}

客户端类

package step1;

import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        // 创建原始对象和备忘录管理者对象
        Originator originator=new Originator();
        Caretaker caretaker=new Caretaker();
        
        // 从文件中读取原始代码框架
        originator.ReadMould();
        
        // 打印显示原始代码框架
        System.out.println(originator.getMould());
        
        // 创建备份
        caretaker.setMemento(originator.createMemento());
        
        // 模拟学生提交最终代码
        Scanner scanner = new Scanner(System.in);
        String mycode = scanner.nextLine();
        originator.setMould(mycode);
        
        // 打印显示修改后的代码框架
        System.out.println(originator.getMould());
        
        // 恢复备份并显示
        originator.restoreMemento(caretaker.getMemento());
        System.out.println(originator.getMould());
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/199268.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中兴小鲜50 ZTE 畅行50 刷机救砖演示机7543n root 虎贲 展锐 T760 解锁BL

系统信息 网络制式 支持中国移动、中国电信、中国联通、中国广电四大运营商5G频段&#xff1b;支持4G/3G/2G 系统平台 MyOS 13.0&#xff08;基于Android 13&#xff09; 硬件信息 处理器 展锐T760&#xff0c;高性能8核5G芯片 存储 6GB RAM128GB ROM 扩展 不支持 电池容…

linux zsh终端美化

目前的centos系统默认的shell还是bash&#xff0c;但是zsh被称为终极shell&#xff0c;国外有个程序员开发出了一个能够让你快速上手的zsh项目&#xff0c;叫做「oh my zsh」&#xff0c;Github 网址是&#xff1a;https://github.com/robbyrussell/oh-my-zsh 有了这玩意zsh用起…

Apache Airflow (十四) :Airflow分布式集群搭建及测试

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

物理层之三种数据交换方式(电路交换、报文交换、分组交换(数据报方式、虚电路方式))

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

AI模特换装的前端实现

本文作者为 360 奇舞团前端开发工程师 随着AI的火热发展&#xff0c;涌现了一些AI模特换装的前端工具&#xff08;比如weshop网站&#xff09;&#xff0c;他们是怎么实现的呢&#xff1f;使用了什么技术呢&#xff1f;下文我们就来探索一下其实现原理。 总体的实现流程如下&am…

NX二次开发UF_MTX3_mtx4 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_MTX3_mtx4 Defined in: uf_mtx.h void UF_MTX3_mtx4(const double mtx_3D [ 9 ] , double mtx_4D [ 16 ] ) overview 概述 Converts a 3D matrix to a 4D matrix with a scale …

Anaconda离线下载torch与安装包

一、下载离线安装包 命令&#xff1a; pip download 安装包名 -d 安装到文件夹名 -i https://pypi.tuna.tsinghua.edu.cn/simple执行这样的命令就会把安装包的离线文件下载到指定文件夹中。 操作&#xff1a; 打开cmd命令行&#xff0c;并进入相应的目录中。 如果是tor…

比尔盖茨:GPT-5不会比GPT-4好多少,生成式AI已达到极限

比尔盖茨一句爆料&#xff0c;成为机器学习社区热议焦点&#xff1a; “GPT-5不会比GPT-4好多少。” 虽然他已不再正式参与微软的日常运营&#xff0c;但仍在担任顾问&#xff0c;并且熟悉OpenAI领导团队的想法。 消息来自德国《商报》&#xff08;Handelsblatt&#xff09;对…

酷开系统 | 追求娱乐不止一种方式,酷开科技带你开启新体验!

在当今社会&#xff0c;娱乐方式多种多样&#xff0c;人们对于娱乐的需求和追求也在日益增长。然而&#xff0c;传统的娱乐方式已经无法满足大家对于多元化、个性化的体验需求。此时&#xff0c;酷开科技以其独特的视角和领先的技术&#xff0c;为消费者们带来了全新的娱乐体验…

蓝桥杯第229题 迷宫与陷阱 BFS C++ 模拟 带你理解迷宫的深奥

题目 迷宫与陷阱 - 蓝桥云课 (lanqiao.cn)https://www.lanqiao.cn/problems/229/learning/?page1&first_category_id1&name%E8%BF%B7%E5%AE%AB%E4%B8%8E%E9%99%B7%E9%98%B1 思路和解题方法 首先&#xff0c;定义了一个结构体node来表示迷宫中的每个节点&#xff0c;包…

苍穹外卖项目笔记(6)— Redis操作营业状态设置

1 在 Java 中操作 Redis 1.1 Redis 的 Java 客户端 Jedis&#xff08;官方推荐&#xff0c;且命令语句同 redis 命令&#xff09;Lettuce&#xff08;底层基于 Netty 多线程框架实现&#xff0c;性能高效&#xff09;Spring Data Redis&#xff08;对 Jedis 和 Lettuce 进行了…

解密Long型数据传递:Spring Boot后台如何避免精度丢失问题

前端和后端之间的数据传递至关重要。然而&#xff0c;当涉及到Long类型数据时&#xff0c;可能会出现精度丢失问题&#xff0c;这会影响数据的准确性。本文将为你介绍两种解决方案&#xff0c;帮助你确保Long类型数据在前端和后端之间的精确传递。 精度丢失测试 访问:http://l…

基于微信小程序的爱心捐赠平台的设计与实现-计算机毕业设计源码64923

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c; 小程序的爱心捐赠平台被用户普遍使用&#xff0c;为方便…

【计算机网络笔记】以太网

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

数学建模-基于BL回归模型和决策树模型对早产危险因素的探究和预测

整体求解过程概述(摘要) 近年来&#xff0c;全球早产率总体呈上升趋势&#xff0c;在我国&#xff0c;早产儿以每年 20 万的数目逐年递增&#xff0c;目前早产已经成为重大的公共卫生问题之一。据研究,早产是威胁胎儿及新生儿健康的重要因素&#xff0c;可能会造成死亡或智力体…

面试必须要知道的MySQL知识--索引

10 索引 10.1 数据页存储结构 10.1.1 数据页的各个部分 在讲索引之前&#xff0c;让我们看看一个单独的数据页是什么样子的 去除掉一些我们不太需要那么关注的部分后&#xff0c;简化如下&#xff1a; 也就是说平时我们在一个表里插入的一行一行的数据会存储在数据页里&#…

MySQL企业版之Firewall(SQL防火墙)

​​​1. 关于Firewall插件 2. Firewall插件的工作方式 3. Firewall插件测试 4. 总结延伸阅读 1. 关于Firewall插件 Friewall是MySQL企业版非常不错的功能插件之一,启用Firewall功能后,SQL的执行流程见下图示意: 2. Firewall插件的工作方式 Firewall插件的工作机制大概是…

FL Studio水果软件21.1新版!新增Hyper Chorus插件及自动更新功能

我们很高兴地宣布在去年12月发布重大版本更新后&#xff0c;FL Studio在2023年8月正式更新到21.1版。本次更新虽然只是维护性质&#xff0c;但我们还是为大家带来了一些全新的功能&#xff0c;包括通过钢琴卷中的音阶捕捉和自定义音符工具&#xff0c;引入更快、更有创意的音符…

4/150:寻找两个正序数组的中位数⭐

题目&#xff1a;寻找两个正序数组的中位数 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (mn)) 。 题解1&#xff1a;暴力 暴力思路简介&#xff0c;…

实测有效的 8 个顶级Android 数据恢复工具

由于我们现在生活在一个依赖数字数据的时代&#xff0c;当重要文件从我们的 Android 手机中消失时&#xff0c;这将是一场数字噩梦。如果您没有预先备份Android手机上的数据或未能通过备份找到已删除的数据&#xff0c;那么选择最好的Android数据恢复软件是最佳选择。 因此&am…