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

news2024/11/18 14:27:44

一、迭代器模式

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());
    }
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序 老年人心血管健康知识科普系统

本系统的功能有管理员&#xff1a;个人中心&#xff0c;用户管理&#xff0c;热点信息管理&#xff0c;疾病管理&#xff0c;疾病类型管理&#xff0c;治疗管理&#xff0c;治疗类型管理&#xff0c;护理管理&#xff0c;护理类型管理&#xff0c;科普管理&#xff0c;科普类型…

Microsoft Office Exce-筛选后的公式批量复制粘贴为值 并且不乱数据

Microsoft Office Exce-利用选择性粘贴将筛选后的公式结果批量转换为值 1、写好【客单价】公式&#xff0c;并下拉填充 &#xff08;【SKU】、【销售额】、【销售量】这三列都是常量&#xff0c;非公式&#xff09; 2、复制客单价公式到E列 3、筛选数据&#xff0c; 按 Delet…

成员内部类(内部类) - Java

成员内部类 说明&#xff1a;成员内部类是定义在外部类的成员位置&#xff0c;并且没有static修饰。 可以直接访问外部类的所有成员&#xff0c;包含私有的。【案例a】可以添加任意访问修饰符&#xff08;public、protected、默认、private&#xff09;&#xff0c;因为它的地…

数组中的第 K 个最大元素(C++实现)

数组中的第 K 个最大元素 题目思路代码 题目 数组中的第 K 个最大元素 思路 通过使用优先队列&#xff08;最大堆&#xff09;来找到数组中第k大的元素。通过弹出最大堆中的前k-1个元素&#xff0c;留下堆中的顶部元素作为结果返回。 代码 class Solution { public:int find…

某东大厂面试js手写题【手写代码附带注释,放心食用,博主亲测】

文章目录 前言js实现push方法js实现订阅发布手写防抖节流手写reduce方法深拷贝es5去重数组多维数组去重排序简单递归实现树形结构输出遍历后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端面试 &#x1f431;‍&#x1f453;博主在前…

摄影网站的技术 SEO:提示和最佳实践

摄影就是要给人留下良好的第一印象。如果你想在竞争中领先&#xff0c;摄影师的SEO是您可以采用的最佳营销方法之一。 我们都曾有过这样的经历&#xff1a;你建立了一个漂亮的作品集网站来吸引更多的业务。网站上线并在社交媒体上推广后&#xff0c;您就可以坐等了。网站访问量…

线程池在Java中的应用实践

摘要&#xff1a;在实际业务场景中&#xff0c;线程池发挥着重要作用。本文将详细解答在高并发、任务执行时间短、并发不高、任务执行时间长以及并发高、业务执行时间长的业务场景下&#xff0c;如何使用线程池进行优化。 一、高并发、任务执行时间短的业务场景 在高并发、任务…

python服装电商系统vue购物商城django-pycharm毕业设计项目推荐

系统面向的使用群体为商家和消费者&#xff0c;商家和消费者所承担的功能各不相同&#xff0c;所对象的权限也各不相同。对于消费者和商家设计的功能如下&#xff1a; 对于消费者设计了五大功能模块&#xff1a; &#xff08;1&#xff09; 商品信息&#xff1a;用户可在商品…

【黑马甄选离线数仓day06_核销主题域开发】

1. 核销主题_DWD和DWM层 1.0 ODS层 操作数据存储层: Operate Data Store 核心理念: 几乎和源数据保持一致,粒度相同 注意事项: 同步方式(全量同步,全量覆盖,增量仅新增,增量新增和更新) 内部表 分区表(部分) 指定字符分隔符 orc zlib 第二天的时候已经完成了从mysql以及sq…

蓝蜂虚拟网络工具配置说明

虚拟网络工具配置说明 注意&#xff1a; 1、在使用虚拟网络工具前&#xff0c;需保证EG20网关可以连接到EMCP云平台&#xff0c;并且设备已经绑定在对应的账号下&#xff0c;同时固件版本为v1.6.6以上。如果不是&#xff0c;点击固件版本处的更新&#xff0c;如下图所示。 2…

GitHub----使用记录

一、上传文件到仓库 1、首先新建一个github仓库 然后先记住这一句指令 2、下载git工具 https://git-scm.com/downloads 下载工具安装不用运行 3、使用git工具上传文件并推送 找到你想上传的文件的位置&#xff0c;右击git Bush here git init &#xff1a;初始化这个仓…

【Python 训练营】N_11 模拟进度条

题目 格式化输出进度条&#xff0c;具体格式如下&#xff1a; 分析 需要格式化打印&#xff0c;进度条随时间显示进展&#xff0c;需要用time模块的sleep()函数。 答案 import time # 导入time模块 length 100 # 定义进度长度模块 for i in range(1,length1): # 遍历1&…

Corel产品注册机Corel Products KeyGen 2023 – XFORCE解决会声会影2023试用30天

CorelDRAW注册机2023支持全系列产品_Corel Products KeyGen 2023 X-FORCE v8 CorelDRAW注册机2023支持全系列产品_Corel Products KeyGen 2023 X-FORCE v8&#xff0c;Corel产品注册机&#xff08;Corel Products KeyGen 2023 – XFORCE&#xff09;&#xff0c;支持Corel旗下所…

TDL CDL信道模型

文章目录 一 TDL二 CDL三 CDL TDL区别 TDL&#xff1a;(Tapped Delay Line&#xff0c;抽头延迟线) CDL&#xff1a;(Clustered Delay Line&#xff0c;集群延迟线) 一 TDL 定义&#xff1a;由一组不同衰落系数和不同时延的抽头组成。全频率范围为&#xff1a;0.5GHz~100GHz&am…

【刷题笔记】分糖果||数组||暴力通过||符合思维方式||多案例分析

分发糖果 文章目录 分发糖果1 题目描述2 题目分析2.1 寻找波峰波谷2.2 从波底往波峰攀爬&#xff01;2.2 计算糖果 3 代码附录1 1 题目描述 https://leetcode.cn/problems/candy/ n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&…

怎么判断香港服务器的性能好不好?

随着互联网的不断发展&#xff0c;越来越多的人开始使用香港服务器来搭建自己的网站或者应用。但是&#xff0c;对于初次使用香港服务器的用户来说&#xff0c;往往会遇到一个问题&#xff1a;怎么判断香港服务器的性能好不好? 首先我们需要了解香港服务器的性能主要取决于哪些…

智能优化算法应用:基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝙蝠算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

iconfont 使用彩色图标

1、下载iconfont到本地 2、全局安装 iconfont-tools npm install -g iconfont-tools 3、在iconfont解压目录下执行命令、一直回车 iconfont-tools 4、文件拷贝 执行完上述命令后会生成iconfont-weapp目录&#xff0c;将iconfont-weapp目录下的iconfont-weapp- icon.css文件…

二叉树之推排序(升序)

目录 1.思路1.1大堆的建立方法1.2排序的方法 2.代码实现以及测试代码 1.思路 如何将一个堆进行排序&#xff0c;并变成升序&#xff1f;首先&#xff0c;如果要完成升序&#xff0c;那我们可以建立一个大堆&#xff0c;因为大堆可以选出一个最大的值放在堆的最上面&#xff0c…

舞蹈店管理系统服务预约会员小程序效果如何

舞蹈的作用很广&#xff0c;也有大量求学者&#xff0c;每个城市也有大小各异的舞蹈品牌店&#xff0c;他们承接商演、也会教学员、宣传拓展生意等&#xff0c;因此近些年来&#xff0c;随着互联网深入及短视频&#xff0c;舞蹈业市场规模也在增加。 而在门店经营中&#xff0…