- 13、责任链模式(对象模式)
- 意图
- 适用性
- 代码实现
- 14、命令模式(对象模式)
- 意图
- 适用性
- 代码实现
- 15、解释器模式(类模式)
- 意图
- 适用性
- 代码实现
- 16、迭代器模式(对象模式)
- 意图
- 适用性
- 代码实现
- 17、中介者模式(对象模式)
- 意图
- 适用性
- 代码实现
- 18、备忘录模式(对象模式)
- 意图
- 适用性
- 代码实现
- 19、观察者模式(对象模式)
- 意图
- 适用性
- 代码实现
- 20、状态模式(对象模式)
- 意图
- 适用性
- 代码实现
- 21、策略模式(对象模式)
- 意图
- 适用性
- 代码实现
- 22、模板方法模式(类模式)
- 意图
- 适用性
- 代码实现
- 23、访问者模式(对象模式)
- 意图
- 适用性
- 代码实现
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用性- 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
- 想在不明确指定接收者的情况下向多个对象中的一个提交一 个请求。
- 可处理一个请求的对象集合应被动态指定。
public class ChainOfResponsibilityPattern { public static void main(String[] args) { Handler fudaoyuan = new FuDaoYuan(); Handler yuanzhang = new YuanZhang(); Handler xiaozhang = new XiaoZhang(); fudaoyuan.setNext(yuanzhang); yuanzhang.setNext(xiaozhang); fudaoyuan.HandlerRequest(14); //院长审批通过 } } abstract class Handler { protected Handler next; public void setNext(Handler next) { this.next = next; } public abstract void HandlerRequest(int request); } //辅导员类 class FuDaoYuan extends Handler { // <= 7 审批 @Override public void HandlerRequest(int request) { if (request <= 7) { System.out.println("辅导员审批通过"); } else { if (next != null) { next.HandlerRequest(request); } else { System.out.println("无法审批"); } } } } //院长类 class YuanZhang extends Handler { // <= 15 审批 @Override public void HandlerRequest(int request) { if (request <= 15) { System.out.println("院长审批通过"); } else { if (next != null) { next.HandlerRequest(request); } else { System.out.println("无法审批"); } } } } //校长类 class XiaoZhang extends Handler { // <= 30 审批 @Override public void HandlerRequest(int request) { if (request <= 30) { System.out.println("校长审批通过"); } else { if (next != null) { next.HandlerRequest(request); } else { System.out.println("无法审批"); } } } }
运行结果
院长审批通过!14、命令模式(对象模式) 意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
适用性- 抽象出待执行的动作以参数化某对象。
- 在不同的时刻指定、排列和执行请求。
- 支持取消操作。
- 支持修改日志。
- 用构建在原语操作上的高层操作构造一个系统。
public class CommandPattern { public static void main(String[] args) { Tv tv = new Tv(); // 接收者对象 电视机 Command onCommand = new OnCommand(tv); // 命令对象 开机命令 Command offCommand = new OffCommand(tv); // 命令对象 关机命令 Invoker invoker = new Invoker(); // 请求者 invoker.setCommand(onCommand); // 给请求者设置 开机 命令 invoker.call(); // 请求者去请求命令 System.out.println("======================="); invoker.setCommand(offCommand); // 给请求者设置 关机命令 invoker.call(); // 请求者去请求命令 } } // 请求者 class Invoker { private Command command; // 命令 public void setCommand(Command command) { // 设置请求者 的 请求的命令 this.command = command; } public void call() { // 调用 command.Execute(); } } // 命令接口 interface Command { public void Execute(); // 执行命令 } // 开机命令 class OnCommand implements Command { private Tv tv; public OnCommand(Tv tv) { this.tv = tv; } @Override public void Execute() { tv.OnAction(); } } // 关机命令 class OffCommand implements Command { private Tv tv; public OffCommand(Tv tv) { this.tv = tv; } @Override public void Execute() { tv.OffAction(); } } // 接收者 电视机 class Tv { public void OnAction() { System.out.println("电视机开机了..."); // 开机行为 } public void OffAction() { System.out.println("电视机关机了..."); // 关机行为 } }
运行结果
电视机开机了... ======================= 电视机关机了...15、解释器模式(类模式) 意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器, 这个解释器使用该表示来解释语言中的句子。
适用性当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时, 以下情况效果最好:该文法简单;效率不是一个关键问题。
代码实现import java.util.*; public class InterpreterPattern { public static void main(String[] args) { Context context = new Context(); context.check("A区的开发人员"); context.check("B区的调试人员"); context.check("C区的测试人员"); System.out.println("=========="); context.check("D区的程序员"); context.check("D区的测试员"); context.check("A区的程序员"); } } class Context { private String[] regions = {"A区", "B区", "C区"}; private String[] persons = {"开发人员", "测试人员", "调试人员"}; private NonterminalExprssion nonterminal; public Context() { TerminalExpression region = new TerminalExpression(regions); TerminalExpression person = new TerminalExpression(persons); nonterminal = new NonterminalExprssion(region, person); } public void check(String info) { boolean bool = nonterminal.Interpret(info); if (bool) { System.out.println("识别成功"); } else { System.out.println("识别失败"); } } } interface Expression { public boolean Interpret(String info); } //非终止符解释器 class NonterminalExprssion implements Expression { private TerminalExpression region;//地区终结符集 private TerminalExpression person;//人员终结符集 public NonterminalExprssion(TerminalExpression region, TerminalExpression person) { this.region = region; this.person = person; } @Override public boolean Interpret(String info) { String[] str = info.split("的"); // B区的调试人员 --> str = {"B区", "调试人员"} return region.Interpret(str[0]) && person.Interpret(str[1]); } } //终止符解释器 class TerminalExpression implements Expression { private Set16、迭代器模式(对象模式) 意图set = new HashSet<>(); public TerminalExpression(String[] data) { // for (遍历对象类型 对象名 : 遍历对象) for (String str : data) { set.add(str); // 将符号存入终结符集 } } @Override public boolean Interpret(String info) { return set.contains(info); //判断某符号是否包含于终结符集内 } }
提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。
适用性- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 支持对聚合对象的多种遍历。
- 为遍历不同的聚合结构提供一个统一的接口。
import java.util.*; public class IteratorPattern { public static void main(String[] args) { BookAggregate bookAggregate = new BookAggregate(); String[] books = {"数据结构", "操作系统", "计算机网络", "计算机组成原理"}; double[] prices = {10.24, 20.48, 40.96, 81.92}; for (int i = 0; i < 4; i ++ ) { bookAggregate.Add(new Book(books[i], prices[i])); } Iterator bookIterator = bookAggregate.CreateIterator(); while (bookIterator.hasNext()) { Book book = (Book) bookIterator.next(); System.out.println(book.getName() + " " + book.getPrice()); } } } interface Iterator { public boolean hasNext(); public Object next(); } class BookIterator implements Iterator { private int index; private BookAggregate bookAggregate; public BookIterator(BookAggregate bookAggregate) { this.index = 0; this.bookAggregate = bookAggregate; } @Override public boolean hasNext() { if (index < bookAggregate.getSize()) { return true; } else { return false; } } @Override public Object next() { Object obj = bookAggregate.get(index); index ++ ; return obj; } } interface Aggregate { public Iterator CreateIterator(); } class BookAggregate implements Aggregate { private Listlist = new ArrayList (); public void Add(Book book) { list.add(book); } public Book get(int index) { return list.get(index); } public int getSize() { return list.size(); } @Override public Iterator CreateIterator() { return new BookIterator(this); } } class Book { private String name; private double price; public Book(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } }
运行结果
数据结构 10.24 操作系统 20.48 计算机网络 40.96 计算机组成原理 81.9217、中介者模式(对象模式) 意图
用一个中介对象来封装一系列的对象交互。 中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
适用性- 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
- 想定制一个分布在多个类中的行为,而又不想生成太多的子类。
public class MediatorPattern { public static void main(String[] args) { ConcreteMediator mediator = new ConcreteMediator(); Colleague1 colleague1 = new Colleague1(mediator); Colleague2 colleague2 = new Colleague2(mediator); mediator.setColleague1(colleague1); mediator.setColleague2(colleague2); colleague1.sendMessage("软考加油"); colleague2.sendMessage("祝大家软考顺利通过!"); } } abstract class Colleague { protected Mediator mediator; } class Colleague1 extends Colleague { public Colleague1(Mediator mediator) { this.mediator = mediator; } public void sendMessage(String message) { mediator.sendMessage(message, this); } public void Notify(String message) { System.out.println("同事1收到消息:" + message); } } class Colleague2 extends Colleague { public Colleague2(Mediator mediator) { this.mediator = mediator; } public void sendMessage(String message) { mediator.sendMessage(message, this); } public void Notify(String message) { System.out.println("同事2收到消息:" + message); } } abstract class Mediator { public abstract void sendMessage(String message, Colleague colleague); } class ConcreteMediator extends Mediator { private Colleague1 colleague1; private Colleague2 colleague2; public void setColleague1(Colleague1 colleague1) { this.colleague1 = colleague1; } public void setColleague2(Colleague2 colleague2) { this.colleague2 = colleague2; } public void sendMessage(String message, Colleague colleague) { if (colleague == colleague1) { colleague2.Notify(message); // 让同事2收到消息 } else { colleague1.Notify(message); // 让同事1收到消息 } } }
运行结果
同事2收到消息:软考加油 同事1收到消息:祝大家软考顺利通过!18、备忘录模式(对象模式) 意图
在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
适用性- 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
import java.util.*; public class MementoPattern { public static void main(String[] args) { Caretaker caretaker = new Caretaker(); Originator originator = new Originator(); originator.setState("1024"); Memento backup1 = originator.createMemento(); caretaker.addMemento(backup1); originator.setState("2048"); Memento backup2 = originator.createMemento(); caretaker.addMemento(backup2); originator.setState("4096"); Memento backup3 = originator.createMemento(); caretaker.addMemento(backup3); System.out.println(originator.getState() + "n");//输出人当前记录的备忘录 caretaker.showMemento();//手机里面的虚拟管理员显示出所有备忘录列表 Memento memento1 = caretaker.getMemento(2); originator.setMemento(memento1); System.out.println("n根据第2次备份还原之后的状态为:" + originator.getState()); } } // 原发器 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 setMemento(Memento memento) { state = memento.getState(); } } // 备忘录 class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } } // 管理者 class Caretaker { private ListmementoList = new ArrayList<>(); public void addMemento(Memento memento) { mementoList.add(memento); } public Memento getMemento(int index) { // 判断参数是否合法 if (index >= 1 && index <= mementoList.size()) { return mementoList.get(index - 1); } return null; } public void showMemento() { int cnt = 1; // for (遍历对象类型 对象名 : 遍历对象) for (Memento memento : mementoList) { System.out.println("第" + cnt + "次备份,状态为:" + memento.getState()); cnt ++ ; } } }
运行结果
4096 第1次备份,状态为:1024 第2次备份,状态为:2048 第3次备份,状态为:4096 根据第2次备份还原之后的状态为:204819、观察者模式(对象模式) 意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
适用性- 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的。
import java.util.*; public class ObserverPattern { public static void main(String[] args) { Subject subjectA = new ConcreteSubject("目标A"); Observer observerB = new ConcreteObserver("张三", subjectA); Observer observerC = new ConcreteObserver("李四", subjectA); Observer observerD = new ConcreteObserver("王五", subjectA); subjectA.setState("更新了"); System.out.println("======================================"); subjectA.Detach(observerD); subjectA.setState("停更了"); } } interface Subject { // 目标 public void Attach(Observer observer); // 添加观察者 public void Detach(Observer observer); // 删除观察者 public void Notify(); // 状态改变后 通知所有观察者 public void setState(String state); // 设置状态(改变状态) public String getState(); // 获取状态 } class ConcreteSubject implements Subject { private String name; private String state; private ListobserverList; public ConcreteSubject(String name) { state = "未更新"; this.name = name; observerList = new ArrayList (); } public void setState(String state) { this.state = state; System.out.println(name + "的状态发生变化,变化后的状态为:" + state); Notify(); } public String getState() { return state; } public void Attach(Observer observer) { observerList.add(observer); } public void Detach(Observer observer) { observerList.remove(observer); } public void Notify() { // for (遍历对象类型 对象名 : 遍历对象) for (Observer observer : observerList) { observer.update(); } } } interface Observer { // 观察者接口 public void update(); // 收到通知 更新观察者的状态 } class ConcreteObserver implements Observer { private String name; private String state; private Subject subject; public ConcreteObserver(String name, Subject subject) { this.name = name; this.subject = subject; subject.Attach(this); state = subject.getState(); } @Override public void update() { System.out.println(name + "收到通知"); state = subject.getState(); // 让当前观察者的状态 和 改变了状态之后的目标的状态保持一致 System.out.println(name + "改变后的状态为:" + state); } }
运行结果
目标A的状态发生变化,变化后的状态为:更新了 张三收到通知 张三改变后的状态为:更新了 李四收到通知 李四改变后的状态为:更新了 王五收到通知 王五改变后的状态为:更新了 ====================================== 目标A的状态发生变化,变化后的状态为:停更了 张三收到通知 张三改变后的状态为:停更了 李四收到通知 李四改变后的状态为:停更了20、状态模式(对象模式) 意图
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
适用性- 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。
public class StatePattern { public static void main(String[] args) { Context context = new Context(); // count:3 System.out.println(context.getState()); context.Request(); // 购买一个饮料 count = 2 context.Request(); // 购买一个饮料 count = 1 context.Request(); // 购买一个饮料 count = 0 System.out.println(context.getState()); context.Request(); // 无货 等待补货 补货成功 count = 5 System.out.println(context.getState()); context.Request(); // 购买一个饮料 count = 4 System.out.println(context.getCount()); } } class Context { // 贩卖机 private int count; private State state; public Context() { count = 3; state = new StateA(); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public State getState() { return state; } public void setState(State state) { this.state = state; } public void Request() { // 购买一个饮料 state.Handle(this); } } interface State { public void Handle(Context context); } class StateA implements State { // 有货 @Override public void Handle(Context context) { int count = context.getCount(); if (count >= 1) { System.out.println("购买成功!"); context.setCount(count - 1); if (context.getCount() == 0) { context.setState(new StateB()); } } else { System.out.println("购买失败!"); } } } class StateB implements State { // 无货 @Override public void Handle(Context context) { int count = context.getCount(); if (count == 0) { System.out.println("购买失败!等待补货"); context.setCount(5); System.out.println("补货成功,请重新购买"); context.setState(new StateA()); } } }
运行结果
Shejims.StatePattern.StateA@1b6d3586 购买成功! 购买成功! 购买成功! Shejims.StatePattern.StateB@4554617c 购买失败!等待补货 补货成功,请重新购买 Shejims.StatePattern.StateA@74a14482 购买成功! 421、策略模式(对象模式) 意图
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
适用性- 许多相关的类仅仅是行为有异。
- 需要使用一个算法的不同变体。
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的Strategy类中,以代替这些条件语句。
public class StrategyPattern { public static void main(String[] args) { Strategy add = new AddStrategy(); Strategy subtraction = new SubtractionStrategy(); Strategy multiply = new MultiplyStrategy(); OperationContext context = new OperationContext(add); System.out.print("两数相加:"); context.Operation(2022, 528); context = new OperationContext(subtraction); System.out.print("两数相减:"); context.Operation(2022, 528); context = new OperationContext(multiply); System.out.print("两数相乘:"); context.Operation(2022, 528); } } class OperationContext { private Strategy strategy; public OperationContext(Strategy strategy) { this.strategy = strategy; } public void Operation(int a, int b) { strategy.TwoNumberOperation(a, b); } } interface Strategy { public void TwoNumberOperation(int a, int b); } //相加策略 class AddStrategy implements Strategy { @Override public void TwoNumberOperation(int a, int b) { System.out.println(a + b); } } //相减策略 class SubtractionStrategy implements Strategy { @Override public void TwoNumberOperation(int a, int b) { System.out.println(a - b); } } //相乘策略 class MultiplyStrategy implements Strategy { @Override public void TwoNumberOperation(int a, int b) { System.out.println(a * b); } }
运行结果
两数相加:2550 两数相减:1494 两数相乘:106761622、模板方法模式(类模式) 意图
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
适用性- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。
- 控制子类扩展。模板方法旨在特定点调用“hook” 操作(默认的行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。
public class TemplateMethodPattern { public static void main(String[] args) { // 父类名 对象名 = new 子类名(); Person student = new Student(); Person teacher = new Teacher(); student.TemplateMethod(); System.out.println("=====我是分割线====="); teacher.TemplateMethod(); } } abstract class Person { public void TemplateMethod() { System.out.println("上课 去教室"); // 1 PrimitiveOperation1(); // 2 System.out.println("下课 离开教室"); // 3 PrimitiveOperation2(); // 4 } public abstract void PrimitiveOperation1(); // 原语操作 1 :上课过程 学生 听课…… 老师 讲课 public abstract void PrimitiveOperation2(); // 原语操作 2 :作业 学生 写作业 提交作业…… 老师 批改作业 打分数 } class Student extends Person { @Override public void PrimitiveOperation1() { System.out.println("学生:听课 学习 做笔记 提出问题"); } @Override public void PrimitiveOperation2() { System.out.println("学生:写作业 提交作业"); } } class Teacher extends Person { @Override public void PrimitiveOperation1() { System.out.println("老师:上课 讲课 解答问题 布置作业"); } @Override public void PrimitiveOperation2() { System.out.println("老师:批改作业 打分数"); } }
运行结果
上课 去教室 学生:听课 学习 做笔记 提出问题 下课 离开教室 学生:写作业 提交作业 =====我是分割线===== 上课 去教室 老师:上课 讲课 解答问题 布置作业 下课 离开教室 老师:批改作业 打分数23、访问者模式(对象模式) 意图
表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
适用性- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作“污染”这些对象的类。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
import java.util.*; public class VisitorPattern { public static void main(String[] args) { PersonStructure structure = new PersonStructure(); Visitor1 visitor1 = new Visitor1(); System.out.println("访问者1的访问记录:"); structure.Accept(visitor1); System.out.println("学生年龄总和:" + visitor1.getStudentAgeSum() + " 老师年龄总和:" + visitor1.getTeacherAgeSum()); System.out.println("========================================="); Visitor2 visitor2 = new Visitor2(); System.out.println("访问者2的访问记录:"); structure.Accept(visitor2); System.out.println("学生最高成绩:" + visitor2.getMaxScore() + " 老师最大工龄:" + visitor2.getMaxWorkYear()); } } interface Visitor { public void visitStudent(Student student); // 访问学生 public void visitTeacher(Teacher teacher); // 访问老师 } class Visitor1 implements Visitor { // 访问者1 分别统计学生和老师的年龄总和 private int studentAgeSum = 0; private int teacherAgeSum = 0; public int getStudentAgeSum() { return studentAgeSum; } public int getTeacherAgeSum() { return teacherAgeSum; } @Override public void visitStudent(Student student) { System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge()); studentAgeSum += student.getAge(); } @Override public void visitTeacher(Teacher teacher) { System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge()); teacherAgeSum += teacher.getAge(); } } class Visitor2 implements Visitor { // 访问者2 分别求出 学生的最高成绩 以及 老师的最高工龄 private int maxScore = -1; private int maxWorkYear = -1; public int getMaxScore() { return maxScore; } public int getMaxWorkYear() { return maxWorkYear; } @Override public void visitStudent(Student student) { System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore()); maxScore = Math.max(maxScore, student.getScore()); } @Override public void visitTeacher(Teacher teacher) { System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear()); maxWorkYear = Math.max(maxWorkYear, teacher.getWorkYear()); } } class PersonStructure { private ListpersonList = new ArrayList (); public PersonStructure() { personList.add(new Student("张三", 21, 89)); personList.add(new Student("李四", 22, 75)); personList.add(new Student("王五", 20, 95)); personList.add(new Teacher("李老师", 35, 7)); personList.add(new Teacher("陈老师", 40, 15)); personList.add(new Teacher("刘老师", 27, 3)); } public void Accept(Visitor visitor) { // for (遍历对象类型 对象名 : 遍历对象) for (Person person : personList) { person.Accept(visitor); } } } abstract class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public abstract void Accept(Visitor visitor); } class Student extends Person { private int score; public Student(String name, int age, int score) { super(name, age); this.score = score; } public int getScore() { return score; } @Override public void Accept(Visitor visitor) { visitor.visitStudent(this); } } class Teacher extends Person { private int workYear; public Teacher(String name, int age, int workYear) { super(name, age); this.workYear = workYear; } public int getWorkYear() { return workYear; } @Override public void Accept(Visitor visitor) { visitor.visitTeacher(this); } }
运行结果
访问者1的访问记录: 访问者1访问学生:张三 年龄:21 访问者1访问学生:李四 年龄:22 访问者1访问学生:王五 年龄:20 访问者1访问老师:谢老师 年龄:35 访问者1访问老师:汪老师 年龄:40 访问者1访问老师:王老师 年龄:27 学生年龄总和:63 老师年龄总和:102 =================================== 访问者2的访问记录: 访问者2访问学生:张三 成绩:89 访问者2访问学生:李四 成绩:75 访问者2访问学生:王五 成绩:95 访问者2访问老师:谢老师 工龄:7 访问者2访问老师:汪老师 工龄:15 访问者2访问老师:王老师 工龄:3 学生最高成绩:95 老师最大工龄:15