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

一、迭代器模式

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;}@Overridepublic 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;}@Overridepublic boolean hasNext() {return position < list.size();}@Overridepublic 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>();  // 学生列表@Overridepublic void addStudent(Student student) {this.list.add(student);}@Overridepublic void removeStudent(Student student) {this.list.remove(student);}@Overridepublic 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; // 初始化生命力为100this.atk = 100; // 初始化攻击力为100this.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);}//实现创建迭代器对象的具体方法@Overridepublic 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;  // 设置逆向遍历游标的初始值}@Overridepublic void next() {if (cursor1 < products.size()) {cursor1++;}}@Overridepublic boolean isLast() {return (cursor1 == products.size());}@Overridepublic void previous() {if (cursor2 > -1) {cursor2--;}}@Overridepublic boolean isFirst() {return (cursor2 == -1);}@Overridepublic Object getNextItem() {return products.get(cursor1);}@Overridepublic 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.mzph.cn/news/176127.shtml

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

相关文章

宝塔面板的使用

记录一下&#xff1a; 后台是SpringBoot项目&#xff0c;前台是Vue项目&#xff0c;前后端分离&#xff0c;要用宝塔布署上腾讯云服务器。 后台&#xff1a;配置文件的数据写云端的。有关localhost的要改成云服务器的公网IP。执行package命令&#xff0c;双击。将打包出来的j…

C 语言-循环嵌套-函数

C 语言 - 循环嵌套、函数 1. 循环嵌套 1.1 作用 循环 套 循环。 1.2 使用 需求1&#xff1a; 打印以下图形&#xff1a; * * * * * * * * * * * * * * * *代码&#xff1a; 1、使用循环打印 #include <stdio.h> int main(int argc, char const *argv[]) {for (int i…

云原生CI/CD流水线发布

文章目录 前言k8s组件与操作流程k8s组件创建pod k8s代码&&打包k8s yamldeploymentservicek8s volumesdemo CIgitlabCI runner CD配置git repository安装argo创建argo cd的配置yamlargocd和helm结合argocd hookargocd 发布 RBACoperatorhelmprometheus && grafn…

曝光!WPS用户信息或被盗用,紧急行动,迅软DSE数据加密应时而动!

WPS摊上大事了&#xff01;有用户发现&#xff0c;在WPS更新的一版用户隐私政策中&#xff0c;明确提到&#xff1a;“我们将对您主动上传的文档材料&#xff0c;在处理后作为AI训练的基础材料使用。”换句话说&#xff0c;WPS有可能“白嫖”用户的文档信息&#xff0c;用于投喂…

CVE-2020-11651(SaltStack认证绕过)漏洞复现

简介 SaltStack是使用Python开发的一个服务器基础架构集中化管理平台,底层采用动态的连接总线,使其可以用于编配,远程执行, 配置管理等等。 Salt非常容易设置和维护,而不用考虑项目的大小。从数量可观的本地网络系统,到跨数据中心的互联网部署,Salt设计为在任意数量的…

顺序表总结

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 &#x1f324;️arraylist的简…

JAVA多线程总结

一、概念&#xff1a; 1、什么是多任务 多任务就是在同一时间做多件事情&#xff0c;如边吃饭边玩手机等。看起来是多个任务都在做&#xff0c;本质上我们的大脑在同一时间依旧只做了一件件事情 2、什么是程序 程序是指令和数据的有序集合&#xff0c;其本身没有任…

洗地机应该怎么选?希亦、必胜、米博、添可、小米洗地机实测推荐

作为一个常年测评智能家居的博主&#xff0c;关于洗地机的测评使用这些年也积累了不少的体验感受。以至于常被周边的朋友问到&#xff0c;洗地机到底是不是真的好用&#xff1f;洗地机有什么优点吗&#xff1f;选购的时候应该怎么选呢&#xff1f;洗地机什么牌子比较好呢&#…

chatglm3 vllm部署推理;api访问使用

用fastchat部署暂时有各种问题,参考:https://github.com/lm-sys/FastChat/pull/2622 本篇用vllm运行测试可以使用 1、vllm运行 python -m vllm.entrypoints.api_server --model /***/chatglm/chatglm3-6b/

【C语言】深入理解数据类型转换与运算

文章目录 1.数据类型转换在分析源程序之前&#xff0c;我们需要了解几个基本概念&#xff1a;现在来分析源程序中的变量及其对应的十进制真值以及扩展操作方式&#xff1a; 1.1. short si -32768;1.2. unsigned short usi si;1.3. int i si;1.4. unsigned ui usi; 2&#x…

【开源】基于JAVA的农村物流配送系统

项目编号&#xff1a; S 024 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S024&#xff0c;文末获取源码。} 项目编号&#xff1a;S024&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2…

深度学习18

卷积层 查看每个数据 使用tensorboard查看 池化层 使用数据集进行训练 创建实例&#xff0c;使用tensorboard进行显示 最大池化保留了图片信息&#xff0c;神经网络训练的数据量大大减小&#xff0c;可以加快训练 非线性激活 非线性激活为神经网络加入了一些非线性的特质…

CTFSHOW sqll注入

号过滤绕过 号和不加通配符的 like 是一样的。 还可以使用 < >号来绕过&#xff0c;<> 在mysql中等于! 如果在加一个! 双重否定代表肯定 就是了 空格过滤绕过 /**/ &#xff0c;()&#xff0c;&#xff0c;tab&#xff0c;两个空格 or and xor not 过滤绕过 a…

正点原子linux应用编程——入门篇2

系统信息与系统资源 本章重点学习如何通过Linux系统调用或C库函数获取系统信息&#xff0c;譬如获取系统时间、日期 以及设置系统时间、日期等&#xff1b;除此之外&#xff0c;还会学习Linux系统下的/proc虚拟文件系统&#xff0c;包括/proc 文件系统是什么以及如何从/proc文…

【APUE】进程间通信

目录 一、管道 1.1 匿名管道 1.2 命名管道 二、XSI IPC 2.1 概述 2.2 消息队列 2.2.1 msgget 2.2.2 msgsnd 2.2.3 msgrcv 2.2.4 msgctl 2.2.5 代码示例 2.3 信号量数组 2.3.1 semget 2.3.2 semop 2.3.3 semctl 2.3.4 代码示例 2.3 共享内存 2.3.1 shmget…

selenium已知一个元素定位同级别的另一个元素

1.需求与实际情况 看下图来举例 &#xff08;1&#xff09;需求 想点击test22&#xff08;即序号-第9行&#xff09;这一行中右边的“复制”这一按钮 &#xff08;2&#xff09;实际情况 只能通过id或者class定位到文件名这一列的元素&#xff0c;而操作这一列的元素是不…

零基础可以学编程吗,不懂英语怎么学编程,中文编程工具实例

零基础可以学编程吗&#xff0c;不懂英语怎么学编程&#xff0c;中文编程工具实例 上图是中文编程工具界面、标尺实例。 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#x…

基于单片机体温心率脉搏检测仪系统设计

**单片机设计介绍&#xff0c; 基于单片机体温心率脉搏检测仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机体温心率脉搏检测仪是一种用于检测人体体温、心率和脉搏等基本生理指标的医疗设备。下面是一个简要…

QT 界面切换

先新建一个Widget工程 ui界面设置如下 在添加一个QT设计师界面类 右键点击添加 第二个UI界面设置如下 代码 链接&#xff1a;https://pan.baidu.com/s/1ovDIG2pno9mJ7mMFh2tq3Q 提取码&#xff1a;6q3m –来自百度网盘超级会员V2的分享

python+pytest接口自动化(2)-HTTP协议基础

HTTP协议简介 HTTP 即 HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09;&#xff0c;是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。 设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。HTTP 协议在 OSI 模型…