Java设计模式---行为型模式
本章Java设计模式的行为型模式的介绍,是通过学习视频记录的笔记,欢迎留言指出错误点
1. 模板方法模式
概念:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
结构:
抽象类:负责给出一个算法的轮廓和骨架,它由一个模板方法和若干个基本方法构成(AbstractClass)1)模板方法:定义算法的骨架,按某种顺序调用其包含的基本方法2)基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。可以分为三种:
- 抽象方法:一个抽象方法由抽象类声明、由其具体子类实现
- 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖,也可以直接继承
- 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法(方法名为isXXX,返回类型为boolean类型)和需要子类重写的空方法两种
具体子类:实现抽象类中所定义的抽象方法和钩子方法,是一个顶级逻辑的组成步骤(ConcreteClassBaoCai ConcreteClassCaiXin)
使用场景:
- 算法的整体步骤很固定,个别部分易变
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制
/** * 模板方法模式 * 抽象类(定义模板方法和基本方法) */ public abstract class AbstractClass { public final void cookProcess(){ //第一步:倒油 this.pourOil(); //第二步:热油 this.heatOil(); //第三步:倒蔬菜 this.pourVegetable(); //第四步:倒调味料 this.pourSauce(); //第五步:翻炒 this.fry(); } public void pourOil() { System.out.println("倒油"); } public void heatOil() { System.out.println("热油"); } public abstract void pourVegetable(); public abstract void pourSauce(); public void fry() { System.out.println("炒啊炒啊炒到熟啊"); } } public class ConcreteClassBaoCai extends AbstractClass{ @Override public void pourVegetable() { System.out.println("下锅的蔬菜是包菜"); } @Override public void pourSauce() { System.out.println("下锅的酱料是辣椒"); } } public class ConcreteClassCaiXin extends AbstractClass { @Override public void pourVegetable() { System.out.println("下锅的蔬菜是菜心"); } @Override public void pourSauce() { System.out.println("下锅的酱料是蒜蓉"); } } //测试 //炒手撕包菜 ConcreteClassBaoCai baoCai = new ConcreteClassBaoCai(); baoCai.cookProcess(); System.out.println("------"); //炒蒜蓉菜心 ConcreteClassCaiXin caiXin = new ConcreteClassCaiXin(); caiXin.cookProcess();
2. 策略模式(对象行为模式)
概念:定义一系列算法,并将每个方法封装起来,使他们可以互相替换,且算法的变化不会影响使用算法的客户。是对象行为模式,通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同对象对这些算法进行管理
结构:
抽象策略类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口(Strategy)
具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或者行为(StrategyA StrategyB StrategyC)
环境类:持有一个策略类的引用,最终给客户端调用(SalesMan)
使用场景:
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
- 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
/** * 策略模式 * 抽象策略类 */ public interface Strategy { void show(); } /** * 具体策略类,封装算法 * 为春节准备的促销活动A */ public class StrategyA implements Strategy{ @Override public void show() { System.out.println("买一送一"); } } /** * 具体策略类,封装算法 * 为中秋准备的促销活动B */ public class StrategyB implements Strategy { public void show() { System.out.println("满200元减50元"); } } /** * 具体策略类,封装算法 * 为圣诞准备的促销活动C */ public class StrategyC implements Strategy { public void show() { System.out.println("满1000元加一元换购任意200元以下商品"); } } /** * 环境类 */ public class SalesMan { //持有抽象策略角色的引用 private Strategy strategy; public SalesMan(Strategy strategy) { this.strategy = strategy; } //向客户展示促销活动 public void salesManShow(){ strategy.show(); } public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } } //测试 //春节来了,使用春节促销活动 SalesMan salesMan = new SalesMan(new StrategyA()); //展示促销活动 salesMan.salesManShow(); System.out.println("=============="); //中秋节到了,使用中秋节的促销活动 salesMan.setStrategy(new StrategyB()); //展示促销活动 salesMan.salesManShow(); System.out.println("=============="); //圣诞节到了,使用圣诞节的促销活动 salesMan.setStrategy(new StrategyC()); //展示促销活动 salesMan.salesManShow();
3. 命令模式
概念:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理
结构:
抽象命令类角色:定义命令的接口,声明执行方法(Command)
具体命令角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作(OrderCommand)
实现者/接收者角色:真正执行命令的对象。任何类都可能成为,只要他能够实现命令要求实现的相应功能(SeniorChef)
调用者/请求者角色:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口(Waitor)
使用场景:
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
- 系统需要在不同的时间指定请求、将请求排队和执行请求
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作
/** * 抽象命令类 */ public interface Command { void execute();//只需要定义一个统一的执行方法 } /** * 具体的命令类 */ public class OrderCommand implements Command{ //持有接收者对象 private SeniorChef receiver; private Order order; public OrderCommand(SeniorChef receiver, Order order) { this.receiver = receiver; this.order = order; } @Override public void execute() { System.out.println(order.getDiningTable() + "桌的订单:"); Set<String> keys = order.getFoodDic().keySet(); for (String key : keys) { receiver.makeFood(order.getFoodDic().get(key),key); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(order.getDiningTable() + "桌的饭弄好了"); } } /** * 订单类 */ public class Order { //快餐号码 private int diningTable; //用来存储餐名并记录份数 private Map<String,Integer> foodDic = new HashMap<>(); public int getDiningTable() { return diningTable; } public void setDiningTable(int diningTable) { this.diningTable = diningTable; } public Map<String, Integer> getFoodDic() { return foodDic; } public void setFoodDic(Map<String, Integer> foodDic) { this.foodDic = foodDic; } } /** * 资深大厨类 是命令的Receiver */ public class SeniorChef { public void makeFood(int num,String foodName){ System.out.println(num + "份" + foodName); } } /** * 服务员类(属于请求者角色) */ public class Waitor { private ArrayList<Command> commands;//可以持有很多的命令对象 public Waitor() { commands = new ArrayList<>(); } public void setCommands(Command cmd) { commands.add(cmd); } //发出命令 有订单,厨师开始执行 public void orderUp(){ System.out.println("美女服务员:叮咚,大厨,新订单来了......."); for (int i=0;i<commands.size();i++){ Command command = commands.get(i); if (command != null) command.execute(); } } } //测试 //创建2个order Order order1 = new Order(); order1.setDiningTable(1); order1.getFoodDic().put("西红柿鸡蛋面",1); order1.getFoodDic().put("小杯可乐",2); Order order2 = new Order(); order2.setDiningTable(3); order2.getFoodDic().put("尖椒肉丝盖饭",1); order2.getFoodDic().put("小杯雪碧",1); //创建接收者 SeniorChef receiver = new SeniorChef(); //将订单和接收者封装成命令对象 OrderCommand cmd1 = new OrderCommand(receiver, order1); OrderCommand cmd2 = new OrderCommand(receiver, order2); //创建调用者waitor Waitor invoker = new Waitor(); invoker.setCommands(cmd1); invoker.setCommands(cmd2); //将订单带到柜台 并向厨师喊 订单来了 invoker.orderUp();
4. 职责链模式
概念:又名责任链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止
结构:
抽象处理者角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接(Handler)
具体处理者角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者(GroupLeader Manager GeneralManager)
客户类角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求传递过程
//请假条 public class LeaveRequest { private String name;//姓名 private int num;//请假天数 private String content;//请假内容 public LeaveRequest(String name, int num, String content) { this.name = name; this.num = num; this.content = content; } public String getName() { return name; } public int getNum() { return num; } public String getContent() { return content; } } /** * 职责链模式 * 处理者抽象类 */ public abstract class Handler { protected final static int NUM_ONE = 1; protected final static int NUM_THREE = 3; protected final static int NUM_SEVEN = 7; //该领导处理的请假天数区间 private int numStart; private int numEnd; //领导上面的领导 private Handler nextHandler; //设置请假天数范围 上不封顶 public Handler(int numStart) { this.numStart = numStart; } //设置请假天数范围 public Handler(int numStart, int numEnd) { this.numStart = numStart; this.numEnd = numEnd; } //设置上级领导 public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; } public final void submit(LeaveRequest leave){ if (0 == this.numStart) return; //如果请假天数达到该领导者的处理需求 if (leave.getNum() >= this.numStart){ this.handleLeave(leave); //如果还有上级,并且请假天数超过当前领导的处理范围 if (null != this.nextHandler && leave.getNum() > numEnd){ this.nextHandler.submit(leave);//继续提交 }else{ System.out.println("流程结束"); } } } protected abstract void handleLeave(LeaveRequest leave); } //小组长(具体的处理者) public class GroupLeader extends Handler{ public GroupLeader() { super(Handler.NUM_ONE,Handler.NUM_THREE); } @Override protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("小组长审批:同意。"); } } //部门经理类(具体的处理者) public class Manager extends Handler { public Manager() { super(Handler.NUM_THREE,Handler.NUM_SEVEN); } protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("部门经理审批:同意"); } } //总经理类(具体的处理者) public class GeneralManager extends Handler { public GeneralManager() { super(Handler.NUM_SEVEN); } protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("总经理审批:同意"); } } //测试 LeaveRequest leave = new LeaveRequest("小花", 8, "身体不适"); GroupLeader groupLeader = new GroupLeader(); Manager manager = new Manager(); GeneralManager generalManager = new GeneralManager(); groupLeader.setNextHandler(manager); manager.setNextHandler(generalManager); groupLeader.submit(leave);
5. 状态模式
概念:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为
结构: 环境角色:也称上下文,定义客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理(Context)
抽象状态角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为(LiftState)
具体状态角色:实现抽象状态所对应的行为(OpenningState ClosingState RunningState StoppingState)
使用场景:
- 当一个对象的行为取决于他的状态,并且他必须在运行时根据状态改变他的行为时,就可以考虑使用状态模式
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时
/** * 状态模式 * 抽象状态类 */ public abstract class LiftState { //定义一个环境角色,也就是封装状态的变化引起的功能变化 protected Context context; public abstract void open(); public abstract void close(); public abstract void run(); public abstract void stop(); public void setContext(Context context) { this.context = context; } } //环境角色 public class Context { /** * 定义出所有电梯的状态 */ //开门状态,电梯只能关闭 public final static OpenningState OPENING_STATE = new OpenningState(); //关闭状态,电梯可以运行、停止、开门 public final static ClosingState CLOSING_STATE = new ClosingState(); //运行状态,电梯只能停止 public final static RunningState RUNNING_STATE = new RunningState(); //停止状态,电梯可以开门、运行 public final static StoppingState STOPPING_STATE = new StoppingState(); //定义一个当前电梯状态 private LiftState liftState; public LiftState getLiftState() { return this.liftState; } public void setLiftState(LiftState liftState) { //当前环境改变 this.liftState = liftState; //把当前的环境通知到各个实现类中 this.liftState.setContext(this); } public void open() { this.liftState.open(); } public void close() { this.liftState.close(); } public void run() { this.liftState.run(); } public void stop() { this.liftState.stop(); } } public class OpenningState extends LiftState{ @Override public void open() { System.out.println("电梯门开启..."); } @Override public void close() { //状态修改 super.context.setLiftState(Context.CLOSING_STATE); //调用当前状态中context中的close方法 super.context.close(); } @Override public void run() { System.out.println("OpenningState run"); } @Override public void stop() { } } public class ClosingState extends LiftState{ @Override public void open() { super.context.setLiftState(Context.OPENING_STATE); super.context.open(); } @Override public void close() { System.out.println("电梯门关闭..."); } @Override public void run() { super.context.setLiftState(Context.RUNNING_STATE); super.context.run(); } @Override public void stop() { super.context.setLiftState(Context.STOPPING_STATE); super.context.stop(); } } public class RunningState extends LiftState{ @Override public void open() { } @Override public void close() { } @Override public void run() { System.out.println("电梯正在运行..."); } @Override public void stop() { super.context.setLiftState(Context.STOPPING_STATE); super.context.stop(); } } public class StoppingState extends LiftState{ @Override public void open() { //状态修改 super.context.setLiftState(Context.OPENING_STATE); //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作 super.context.getLiftState().open(); } @Override public void close() { //状态修改 super.context.setLiftState(Context.CLOSING_STATE); //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作 super.context.getLiftState().close(); } @Override public void run() { //状态修改 super.context.setLiftState(Context.RUNNING_STATE); //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作 super.context.getLiftState().run(); } @Override public void stop() { System.out.println("电梯停止了..."); } } //测试 //创建环境角色对象 Context context = new Context(); //设置当前电梯装填 // context.setLiftState(new OpenningState()); context.setLiftState(new ClosingState()); // context.setLiftState(new RunningState()); // context.setLiftState(new StoppingState()); context.open(); context.run(); context.close(); context.stop();
6. 观察者模式
概念:又称为发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己
结构:
抽象主题:把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增删观察者(Subject)
具体主题:将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知(SubscriptionSubject)
抽象观察者类:观察者的抽象类,定义一个更新接口,使得在得到主题更改通知时更新自己(Observer)
具体观察者:实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态(WeixinUser)
使用场景:
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时
/** * 观察者模式 * 抽象观察者类 */ public interface Observer { void update(String message); } /** * 具体观察者角色类 * 被观察者 */ public class WeixinUser implements Observer{ private String name; public WeixinUser(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "-" + message); } } //抽象主题角色类 public interface Subject { //添加订阅者(添加观察者对象) void attach(Observer observer); //删除订阅者 void detach(Observer observer); //通知订阅者更新消息 void notify(String message); } /** * 具体主题角色类 * 观察者 */ public class SubscriptionSubject implements Subject{ //定义一个集合,存储多个观察者对象 private List<Observer> weixinUserList = new ArrayList<Observer>(); @Override public void attach(Observer observer) { weixinUserList.add(observer); } @Override public void detach(Observer observer) { weixinUserList.remove(observer); } @Override public void notify(String message) { for (Observer observer : weixinUserList) { observer.update(message); } } } //测试 //1.创建公众号对象 SubscriptionSubject subject = new SubscriptionSubject(); //2.订阅公众号 subject.attach(new WeixinUser("孙悟空")); subject.attach(new WeixinUser("猪悟能")); subject.attach(new WeixinUser("沙悟净")); //3.公众号更新,发出消息给订阅者(观察者对象) subject.notify("更新了");
7. 中介者模式
概念:又名调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变他们之间的交互
结构:
抽象中介者角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法(Mediator)
具体中介者角色:实现中介者接口,定义一个list来管理同事对象,协调各个同事角色之间的交互关系,因此依赖于同事角色(MediatorStructure)
抽象同事类角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有互相影响的同事类的公共功能(Person)
具体同事类角色:抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互(HouseOwner Tenant)
使用场景:
- 系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解
- 想创建一个运行于多个类之间的对象,又不想生成新的子类时
/** * 中介者模式 * 抽象中介者类 */ public abstract class Mediator { //申明一个联络方法 public abstract void constact(String message,Person person); } //抽象同事类 public class Person { protected String name; protected Mediator mediator; public Person(String name, Mediator mediator) { this.name = name; this.mediator = mediator; } } /** * 具体的同事角色类 * 房主 */ public class HouseOwner extends Person{ public HouseOwner(String name, Mediator mediator) { super(name, mediator); } //与中介者联系 public void constact(String message){ mediator.constact(message,this); } //获取信息 public void getMessage(String message){ System.out.println("房主" + name +"获取到的信息:" + message); } } //具体同事类 承租人 public class Tenant extends Person { public Tenant(String name, Mediator mediator) { super(name, mediator); } //与中介者联系 public void constact(String message){ mediator.constact(message, this); } //获取信息 public void getMessage(String message){ System.out.println("租房者" + name +"获取到的信息:" + message); } } /** * 具体的中介者角色类 * 中介机构 */ public class MediatorStructure extends Mediator { //首先中介结构必须知道所有房主和租房者的信息 private HouseOwner houseOwner; private Tenant tenant; public HouseOwner getHouseOwner() { return houseOwner; } public void setHouseOwner(HouseOwner houseOwner) { this.houseOwner = houseOwner; } public Tenant getTenant() { return tenant; } public void setTenant(Tenant tenant) { this.tenant = tenant; } @Override public void constact(String message, Person person) { if (person == houseOwner){ tenant.getMessage(message); }else{ houseOwner.getMessage(message); } } } //测试 //一个房主、一个租房者、一个中介机构 MediatorStructure mediator = new MediatorStructure(); //房主和租房者只需要知道中介机构即可 HouseOwner houseOwner = new HouseOwner("张三", mediator); Tenant tenant = new Tenant("李四", mediator); //中介结构要知道房主和租房者 mediator.setHouseOwner(houseOwner); mediator.setTenant(tenant); tenant.constact("需要租三室的房子"); houseOwner.constact("我这有三室的房子,你需要租吗?");
8. 迭代器模式
概念:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象内部表示
结构:
抽象聚合角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口(StudentAggregate)
具体聚合角色:实现抽象聚合类,返回一个具体迭代器的实例(StudentAggregateImpl)
抽象迭代器角色:定义访问和遍历聚合元素的接口,通常包含hasNext()、next()方法(StudentIterator)
具体迭代器角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置(StudentIteratorImpl)
public class Student { private String name; private String 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; } public Student(String name, String number) { this.name = name; this.number = number; } public Student() { } } /** * 迭代器模式 * 抽象迭代器角色接口 */ public interface StudentIterator { //判断是否还有元素 boolean hasNext(); //获取下一个元素 Student next(); } /** * 抽象聚合角色接口 */ public interface StudentAggregate { //添加学生功能 void addStudent(Student stu); //删除学生功能 void removeStudent(Student stu); //获取迭代器对象功能 StudentIterator getStudentIterator(); } public class StudentAggregateImpl implements StudentAggregate{ private List<Student> list = new ArrayList<>(); @Override public void addStudent(Student stu) { list.add(stu); } @Override public void removeStudent(Student stu) { list.remove(stu); } @Override public StudentIterator getStudentIterator() { return new StudentIteratorImpl(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; } } //测试 //创建聚合对象 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()); }
9. 访问者模式
概念:封装一些作用于某种数据结构中的各元素的操作,它可以再不改变这个数据结构的前提下定义作用于这些元素的新的操作
结构:
抽象访问者角色:定义了对每一个元素(Element)访问的行为,它的参数是可以访问的元素,他的方法个数理论上来讲与元素类个数(Element的实现类个数)是一样的,访问者模式要求元素类的个数不能改变(Person)
具体访问者角色:给出对每一个元素类访问时所产生的具体行为(Owner Someone)
抽象元素角色:定义一个接受访问者的方法,每一个元素都要可以被访问者访问(Animal)
具体元素角色:提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法(Dog Cat)
对象结构角色:定义当中所提到的对象结构,对象结构是一个抽象表述,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会含有一组元素,并且可以迭代这些元素,供访问者访问(Home)
使用场景:
- 对象结构相对稳定,但其操作算法经常变化的程序
- 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构
/** * 访问者模式 * 抽象访问者角色类 */ public interface Person { //喂食宠物狗 void feed(Cat cat); //喂食宠物猫 void feed(Dog dog); } //具体访问者角色类(自己) public class Owner implements Person { @Override public void feed(Cat cat) { System.out.println("主人喂食猫"); } @Override public void feed(Dog dog) { System.out.println("主人喂食狗"); } } //具体访问者角色类(其他人) public class Someone implements Person { public void feed(Cat cat) { System.out.println("其他人喂食猫"); } public void feed(Dog dog) { System.out.println("其他人喂食狗"); } } //抽象元素角色类 public interface Animal { //接受访问者访问的功能 void accept(Person person); } /** * 具体元素角色类(宠物狗) */ public class Dog implements Animal { public void accept(Person person) { person.feed(this); //访问者给宠物猫喂食 System.out.println("好好吃,汪汪汪。。。"); } } /** * 具体元素角色类(宠物猫) */ public class Cat implements Animal { public void accept(Person person) { person.feed(this); //访问者给宠物猫喂食 System.out.println("好好吃,喵喵喵。。。"); } } //对象结构类 public class Home { //声明一个集合对象,用来存储元素对象 private List<Animal> nodeList = new ArrayList<>(); //添加元素功能 public void add(Animal animal){ nodeList.add(animal); } public void action(Person person){ //遍历集合,获取每一个元素,让访问者访问每一个元素 for (Animal animal : nodeList) { animal.accept(person); } } } //测试 Home home = new Home(); home.add(new Dog()); home.add(new Cat()); Owner owner = new Owner(); home.action(owner);
10. 备忘录模式
概念:又名快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态
(例子:word撤销操作)
结构:
发起人角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息(GameRole)
备忘录角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人(RoleStateMemento Memento)
管理者角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改(RoleStateCaretaker)
等效接口:
窄接口:管理者(Caretaker)对象(和其他发起人对象之外的任何对象)看到的是备忘录的窄接口,这个窄接口只允许他把备忘录对象传给其他的对象
宽接口:与管理者看到的窄接口相反,发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态
使用场景:
- 需要保存与恢复数据的场景,比如玩游戏时的中间结果的存档功能
- 需要提供一个可回滚操作的场景,如word等软件在编辑时需要Ctrl+Z组合键,还有数据库中的事务操作
/** * 备忘录模式 * 游戏角色类(属于发起人角色) * 白箱备忘录:破坏封装性的 */ public class GameRole { private int vit; //生命力 private int atk; //攻击力 private int def; //防御力 //初始化状态 public void initState(){ vit = 100; atk = 100; def = 100; } //战斗 public void fight(){ vit = 0; atk = 0; 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; } } //备忘录角色类 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; } } //备忘录对象管理对象 public class RoleStateCaretaker { private RoleStateMemento roleStateMemento; public RoleStateMemento getRoleStateMemento() { return roleStateMemento; } public void setRoleStateMemento(RoleStateMemento roleStateMemento) { this.roleStateMemento = roleStateMemento; } } //测试 System.out.println("------------大战Boss前------------"); GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.stateDisplay(); //保存进度 RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setRoleStateMemento(gameRole.saveState()); System.out.println("------------大战Boss后------------"); gameRole.fight(); gameRole.stateDisplay(); System.out.println("------------恢复之前状态------------"); gameRole.recoverState(roleStateCaretaker.getRoleStateMemento()); gameRole.stateDisplay(); //备忘录接口,对外提供窄接口 public interface Memento { } /** * 备忘录模式 * 黑箱备忘录: * 备忘录角色对发起人对象提供一个宽接口,而为其他对象提供一个窄接口 * 实现双重接口方法是将备忘录类设计成发起人类的内部成员类 */ public class GameRole { private int vit; //生命力 private int atk; //攻击力 private int def; //防御力 //初始化状态 public void initState(){ vit = 100; atk = 100; def = 100; } //战斗 public void fight(){ vit = 0; atk = 0; 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; } } } //备忘录对象管理对象 public class RoleStateCaretaker { //声明Memento类型的变量 private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } } //测试 System.out.println("------------大战Boss前------------"); com.project.action.memento.blackBox.GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.stateDisplay(); //保存进度 com.project.action.memento.blackBox.RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setMemento(gameRole.saveState()); System.out.println("------------大战Boss后------------"); gameRole.fight(); gameRole.stateDisplay(); System.out.println("------------恢复之前状态------------"); gameRole.recoverState(roleStateCaretaker.getMemento()); gameRole.stateDisplay();
11. 解释器模式
概念:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识开解释语言中的句子
解释器模式中,需要将待解决的问题,提取出规则,抽象成一种“语言”。比如加减法运算,规则是:由数值和+-符合组成的合法序列
解释器就是要解析出来语句的含义
结构:
抽象表达式角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法interpret()
终结符表达式角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应
非终结符表达式角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式
环境角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值
客户端:主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法
/** * 解释器模式 * 抽象表达式类 */ public abstract class AbstractExpression { public abstract int interpret(Context context); } //环境类 public class Context { private Map<Variable,Integer> map = new HashMap<>(); //添加变量的功能 public void assign(Variable var,Integer value){ map.put(var,value); } //根据变量获取对应的值 public int getValue(Variable var){ return map.get(var); } } //终结符表达式角色 变量表达式 public class Variable extends AbstractExpression{ private String name; public Variable(String name) { this.name = name; } @Override public int interpret(Context context) { return context.getValue(this); } @Override public String toString() { return name; } } //非终结符表达式角色 加法表达式 public class Plus extends AbstractExpression{ private AbstractExpression left; private AbstractExpression right; public Plus(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) + right.interpret(context); } @Override public String toString() { return "(" + left.toString() + " + " + right.toString() + ")"; } } //非终结符表达式角色 减法表达式 public class Minus extends AbstractExpression { private AbstractExpression left; private AbstractExpression right; public Minus(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) - right.interpret(context); } @Override public String toString() { return "(" + left.toString() + " - " + right.toString() + ")"; } } //测试 Context context = new Context(); Variable a = new Variable("a"); Variable b = new Variable("b"); Variable c = new Variable("c"); Variable d = new Variable("d"); Variable e = new Variable("e"); context.assign(a, 1); context.assign(b, 2); context.assign(c, 3); context.assign(d, 4); context.assign(e, 5); AbstractExpression expression = new Minus(new Plus(new Plus(new Plus(a, b), c), d), e); System.out.println(expression + "= " + expression.interpret(context));