目录
行为型模式用于描述程序在运行时复杂度的流程控制,即描述多个类或者对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。
行为型模式分为:
- 模板方法模式
- 策略模式
- 命令模式
- 职责链模式
- 状态模式
- 观察者模式
- 中介者模式
- 迭代器模式
- 访问者模式
- 备忘录模式
- 解释器模式
以上11中行为型模式,除了模板方法模式和解释器模式时类行为型模式,其他都是对象行为型模式。
一.模板方法模式
1.1 概述
定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中【但是要在父类中进行抽象声明】,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
1.2 结构
模板方法(Template Method)模式包含以下主要角色:
- 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可分为三种:
抽象方法(Abstract Method):一个抽象方法由抽象类声明,有其子类实现。
具体方法(Concrete Method):一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
钩子方法(Hook Method):在抽象类中已经实现,保活用于判断的逻辑方法和需要的子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法一般为isXxx,返回值类型为boolean类型。
- 具体子类(Concrete Class):实现抽象类中定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
1.3 案例
【例】炒菜
AbstractClass抽象类
//抽象类(定义模板方法和基本方法)
public abstract class AbstractClass {
//模板方法定义(不想被改变,加final)
public final void cookProcess(){
pourOil();
heatOil();
pourVegetable();
pourSauce();
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("炒啊炒啊炒到熟啊");
}
}
ConcreteClass_BaoCai具体子类
//炒包菜类
public class ConcreteClass_BaoCai extends AbstractClass {
public void pourVegetable(){
System.out.println("下锅的蔬菜是包菜");
}
public void pourSauce(){
System.out.println("下锅的酱料是辣椒");
}
}
ConcreteClass_CaiXin具体子类
//炒菜心类
public class ConcreteClass_CaiXin extends AbstractClass {
public void pourVegetable(){
System.out.println("下锅的蔬菜是菜心");
}
public void pourSauce(){
System.out.println("下锅的酱料是蒜蓉");
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//炒包菜
//创建对象
ConcreteClass_BaoCai baoCai=new ConcreteClass_BaoCai();
//调用炒菜的功能
baoCai.cookProcess();
System.out.println("========================");
//炒菜心
ConcreteClass_CaiXin caiXin=new ConcreteClass_CaiXin();
caiXin.cookProcess();
}
1.4 优缺点
1.5 使用场景
二.策略模式
2.1 概述
定义:
该模式定义了一系列的算法,并将每个算法封装起来,使它们可以相互替代,且算法的变化不会影响使用算法的客户。策略模式属于对像行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来了,并委派给不同的对象对这些算法进行管理。
2.2 结构
策略模式的主要角色如下:
- 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或者抽象类实现。此角色给出所有具体策略类所需的接口。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体算法实现或行为。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
2.3 案例
【例】促销活动
Strategy抽象策略类
//抽象策略类
public interface Strategy {
void show();
}
StrategyA具体策略类
//具体策略类
public class StrategyA implements Strategy {
public void show(){
System.out.println("买一送一");
}
}
StrategyB具体策略类
//具体策略类
public class StrategyB implements Strategy {
public void show(){
System.out.println("满200减50");
}
}
StrategyC具体策略类
//具体策略类
public class StrategyC implements Strategy {
public void show(){
System.out.println("满1000减500");
}
}
SaleMan环境类
//促销员(环境类)
public class SaleMan {
//聚合策略类对象
private Strategy strategy;
public SaleMan(Strategy strategy) {
this.strategy = strategy;
}
//由促销员展示促销活动给普通用户
public void saleManShow(){
strategy.show();
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//春节来了,使用春节促销活动StrategyA
SaleMan saleMan=new SaleMan(new StrategyA());
saleMan.saleManShow();
System.out.println("==================");
//中秋节,使用中秋节的促销活动StrategyB
SaleMan saleMan2=new SaleMan(new StrategyB());
saleMan2.saleManShow();
System.out.println("==================");
//圣诞节,使用圣诞节的促销活动StrategyB
SaleMan saleMan3=new SaleMan(new StrategyC());
saleMan3.saleManShow();
}
}
2.4 优缺点
2.5 使用场景
2.6 JDK 源码解析
三.命令模式
3.1 概述
定义:
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便命令对象进行存储、传递、调用、增加和管理。
3.2 结构
3.3 案例
服务员:调用者角色,由她来发起命令
资深大厨:接收者角色,真正命令执行的对象
订单:命令中包含订单
Order订单类
//订单类
public class Order {
//餐桌号码
private int diningtable;
//所下的餐品及份数
private Map<String, Integer> foodDir=new HashMap<String, Integer>();;
public void setDiningtable(int diningtable) {
this.diningtable = (int) diningtable;
}
public int getDiningtable() {
return diningtable;
}
public Map<String, Integer> getFoodDir() {
return foodDir;
}
public void setFood(String name, int num) {
foodDir.put(name, num);
}
}
Command抽象命令类
//抽象命令类
public interface Command {
void execute();
}
OrderCommand具体命令类
//具体命令类
public class OrderCommand implements Command{
//持有接收者对象
private SeniorChef reciver;
private Order order;
public OrderCommand(SeniorChef reciver, Order order) {
this.reciver = reciver;
this.order = order;
}
public void execute(){
System.out.println(order.getDiningtable()+"桌的订单:");
Map<String, Integer> foodDir=order.getFoodDir();
//遍历map集合
Set<String> keys=foodDir.keySet();
for(String foodName:keys){
reciver.makeFood(foodName, foodDir.get(foodName));
}
System.out.println(order.getDiningtable()+"桌的饭准备完毕!!!");
}
}
SeniorChef接收者类
//厨师类
public class SeniorChef {
public void makeFood(String name, int num){
System.out.println(num+"份"+name);
}
}
Waitor调用者类
// 服务员类(属于请求者角色)
public class Waitor {
//持有多个命令对象
private List<Command> commands=new ArrayList<Command>();
public void setCommands(Command cmd){
//将cmd对象存储倒list对象中
commands.add(cmd);
}
//发起命令功能 喊 订单来了
public void orderUp(){
System.out.println("Order up。。。。");
//遍历list集合
for(Command cmd:commands){
if(cmd!=null){
cmd.execute();
}
}
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//创建第一个订单对象
Order order1 = new Order();
order1.setDiningtable(1);
order1.setFood("西红柿鸡蛋面",1);
order1.setFood("小杯可乐",2);
//创建第二个订单对象
Order order2 = new Order();
order2.setDiningtable(2);
order2.setFood("尖椒肉丝盖饭",1);
order2.setFood("小杯雪碧",1);
//创建厨师对象
SeniorChef receiver = new SeniorChef();
//创建命令对象
OrderCommand cmd1=new OrderCommand(receiver,order1);
OrderCommand cmd2=new OrderCommand(receiver,order2);
//创建调用者(服务员对象)
Waitor invoke =new Waitor();
invoke.setCommands(cmd1);
invoke.setCommands(cmd2);
//让服务员发起命令
invoke.orderUp();
}
}
3.4 优缺点
3.5 使用场景
四.责任链模式
4.1 概述
定义:
又名责任链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链,当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
4.2 结构
4.3 案例
现在需要开发1一个请假流程控制系统,请假一天以下只需要找小组长同意即可;请假1天到3天需要部门经理同意;请假3天到7天还需要总经理同意才行。
Handler抽象处理者角色
//抽象处理者
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.numEnd = numEnd;
this.numStart = numStart;
}
//设置上级领导对象
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
//各类领导处理请假条的方法
protected abstract void handleLeave(LeaveRequest leave);
//提交请假条
public final void submit(LeaveRequest leave) {
//该领导进行审批
this.handleLeave(leave);
if(this.nextHandler != null && leave.getNum() > this.numEnd) {
this.nextHandler.submit(leave);
}
}
}
GroupLeader具体处理者角色
//小组长类(具体处理者)
public class GroupLeader extends Handler{
public GroupLeader() {
super(0,Handler.NUM_ONE);
}
protected void handleLeave(LeaveRequest leave){
System.out.println(leave.getName()+"请假"+leave.getNum()+"天,"+leave.getContent()+"。");
System.out.println("小组长审批:同意");
}
}
Manager具体处理者角色
//部门经理类(具体处理者)
public class Manager extends Handler{
public Manager() {
super(Handler.NUM_ONE,Handler.NUM_THREE);
}
protected void handleLeave(LeaveRequest leave){
System.out.println(leave.getName()+"请假"+leave.getNum()+"天,"+leave.getContent()+"。");
System.out.println("部门经理审批:同意");
}
}
GeneralManager具体处理者角色
//总经理类(具体处理者)
public class GeneralManager extends Handler{
public GeneralManager() {
super(Handler.NUM_THREE,Handler.NUM_SEVEN);
}
protected void handleLeave(LeaveRequest leave){
System.out.println(leave.getName()+"请假"+leave.getNum()+"天,"+leave.getContent()+"。");
System.out.println("总经理审批:同意");
}
}
LeaveRequest请假条类
//请假条类
public class LeaveRequest {
//姓名
private String name;
//请假天数
public 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 void setName(String name) {
this.name = name;
}
public void setNum(int num) {
this.num = num;
}
public void setContent(String content) {
this.content = content;
}
}
Client客户类角色
public class Client {
public static void main(String[] args) {
//创建一个请假条对象
LeaveRequest leave=new LeaveRequest("小明",1,"身体不适");
//创建各级领导对象
GroupLeader groupLeader=new GroupLeader();
Manager manager=new Manager();
GeneralManager generalManager=new GeneralManager();
//设置处理者链
groupLeader.setNextHandler(manager);
manager.setNextHandler(generalManager);
//小明提交请假申请
groupLeader.submit(leave);
}
}
4.4 优缺点
优点:
缺点:
五.状态模式
5.1 概述
【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态、关门状态、停止状态、运行状态。每一种状态改变,都可能要根据其他状态来更新处理。例如如果电梯现在处于运行时状态,就不能进行开门操作,而如果电梯门是停止状态,就可以执行开门操作。
ILift电梯接口
//电梯接口
public interface ILift {
//定义四个电梯状态的常量
int OPENING_STATE = 1;
int CLOSING_STATE = 2;
int RUNNING_STATE = 3;
int STOPPING_STATE = 4;
//设置电梯状态的功能
void setState(int state);
//电梯操作
void open();
void close();
void run();
void stop();
}
Lift电梯
//电梯类(ILift子实现类)
public class Lift implements ILift{
//声明一个记录当前电梯状态的变量
private int state;
@Override
public void setState(int state) {
this.state = state;
}
public void open(){
switch(state){
//什么都不做
case OPENING_STATE:break;
case CLOSING_STATE:
System.out.println("电梯打开了。。。");
setState(OPENING_STATE);
break;
case STOPPING_STATE:
System.out.println("电梯打开了。。。");
setState(OPENING_STATE);
break;
case RUNNING_STATE:break;
}
}
public void close(){
switch(state){
case OPENING_STATE:
System.out.println("电梯关闭了。。。");
setState(CLOSING_STATE);
break;
case CLOSING_STATE:
break;
case STOPPING_STATE:
break;
case RUNNING_STATE:
break;
}
}
public void run(){
switch(state){
case OPENING_STATE:
break;
case CLOSING_STATE:
System.out.println("电梯开始运行了。。。");
setState(RUNNING_STATE);
break;
case STOPPING_STATE:
System.out.println("电梯开始运行了。。。");
setState(RUNNING_STATE);
break;
case RUNNING_STATE:
break;
}
}
public void stop(){
switch(state){
//什么都不做
case OPENING_STATE:
break;
case CLOSING_STATE:
System.out.println("电梯停止了。。。");
setState(STOPPING_STATE);
break;
case STOPPING_STATE:
break;
case RUNNING_STATE:
System.out.println("电梯停止了。。。");
setState(STOPPING_STATE);
break;
}
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//创建电梯对象
Lift lift = new Lift();
//设置当前电梯状态
lift.setState(ILift.OPENING_STATE);
//打开
lift.open();
lift.close();
lift.run();
lift.stop();
}
}
问题分析:
- 使用了大量的switch。。。case这样的判断(if。。。else也是一样),使程序可读性变差。
- 扩展性很差。如果新增断电状态,我们需要修改上面判断逻辑。
定义:
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,运行状态对象在其内部状态发生改变时改变其行为。
5.2 结构
5.3 案例
5.4 优缺点
5.5 使用场景
六.观察者模式
6.1 概述
定义:
又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态改变时,会通知所有的观察者对象,使它们能够自动更新自己。
6.2 结构
6.3 案例
【例】微信公众号
Subject抽象主题类
//抽象主题角色
public interface Subject {
//添加观察者对象
void attach(Observer observer);
//删除观察者对象
void detach(Observer observer);
//通知观察者更新消息
void notify(String message);
}
SubscriptionSubject具体主题类
//具体主题角色类
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) {
//调用观察者对象中update方法
observer.update(message);
}
}
}
Observer抽象观察者类
//抽象观察者类
public interface Observer {
void update(String message);
}
WeiXinUser具体观察者类
//具体观察者角色类
public class WeiXinUser implements Observer {
private String name;
public WeiXinUser(String name) {
this.name = name;
}
public void update(String message) {
System.out.println("WeiXinUser: " + name + " : " + message);
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//创建公众号对象
SubscriptionSubject subject = new SubscriptionSubject();
//订阅公众号
subject.attach(new WeiXinUser("孙悟空"));
subject.attach(new WeiXinUser("猪八戒"));
subject.attach(new WeiXinUser("沙悟净"));
//公众号更新,发出消息
subject.notify("传智黑马专栏更新。。。");
}
}
6.4 优缺点
6.5 使用场景
七.中介者模式
7.1 概述
定义:
又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间耦合松散,且可以独立改变它们之间的交互。
7.2 结构
7.3 案例
【例】租房
现在租房基本都是通过房屋中介,房主将房屋托管给房屋中介,而租房者从房屋中介获取房屋信息。房屋中介充当租房者与房屋所有者之间的中介者。
Mediator抽象中介者角色
//抽象中介者类
public abstract class Mediator {
public abstract void constact(String message, Person person);
}
MediatorStructure具体中介者角色
//具体中介者角色
public class MediatorStructure extends Mediator {
//聚合房主和租房者对象
private HouseOwner houseOwner;
private Tenant tenant;
public HouseOwner getHouseOwner() {
return houseOwner;
}
public Tenant getTenant() {
return tenant;
}
public void setHouseOwner(HouseOwner houseOwner) {
this.houseOwner = houseOwner;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public void constact(String message, Person person) {
if(person == houseOwner){
houseOwner.getMessage(message);
}
else{
tenant.getMessage(message);
}
}
}
Person抽象同事角色
public abstract class Person {
protected String name;
protected Mediator mediator;
public Person(String name, Mediator mediator) {
this.name = name;
this.mediator = mediator;
}
}
Tenant具体同事角色(租房者)
//具体同事角色
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);
}
}
HouseOwner具体同事角色(房主)
//具体同事角色类
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);
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//创建中介者对象
MediatorStructure mediator = new MediatorStructure();
//创建租房者对象
Tenant tenant=new Tenant("李四",mediator);
//创建房主对象
HouseOwner houseOwner=new HouseOwner("张三",mediator);
//中介者要知道具体的房主和租房者
mediator.setTenant(tenant);
mediator.setHouseOwner(houseOwner);
tenant.constact("我要组三室的房子!!!");
houseOwner.constact("我这里有三室的房子,你要租吗?");
}
}
7.4 优缺点
7.5 使用场景
八.迭代器模式
8.1 概述
定义:
提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
8.2 结构
8.3 案例
【例】定义一个可以存储学生对象的容器对象,将遍历容器的功能交由迭代器实现。
StudentIterator抽象迭代器角色
//抽象迭代器角色接口
public interface StudentIterator {
//判断是否还有元素
boolean hasNext();
//获取下一个元素
Student next();
}
StudentIteratorImpl具体迭代器角色
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 student = list.get(position);
position++;
return student;
}
}
StudentAggregate抽象聚合角色
//抽象聚合角色接口
public interface StudentAggregate {
//添加学生功能
void addStudent(Student student);
//删除学生功能
void removeStudent(Student student);
//获取迭代器对象功能
StudentIterator getStudentIterator();
}
StudentAggregate具体聚合角色
public class StudentAggregateImpl implements StudentAggregate{
private List<Student> list=new ArrayList<Student>();
@Override
public void addStudent(Student student) {
list.add(student);
}
@Override
public void removeStudent(Student student) {
list.remove(student);
}
//获取迭代器对象
@Override
public StudentIterator getStudentIterator() {
return new StudentIteratorImpl(list);
}
}
Student学生类
public class Student {
private String name;
private String number;
public Student() {
}
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 String getNumber() {
return number;
}
public void setName(String name) {
this.name = name;
}
public void setNumber(String number) {
this.number = number;
}
}
Client测试类
public class Client {
public static void main(String[] args) {
//创建聚合对象
StudentAggregate 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()) {
System.out.println(iterator.next());
}
}
}
8.4 优缺点
8.5 使用场景
九.访问者模式
9.1 概述
定义:
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
9.2 结构
9.3 案例
【例】给宠物喂食
现在养宠物的人特别多,我们就以这个为例,当然宠物还分为狗、猫等,要给宠物喂食的话,主人可以喂,其他人也可以喂食。
- 访问者角色:给宠物喂食的人
- 具体访问者角色:主人、其他人
- 抽象元素角色:动物抽象类
- 具体元素角色:宠物狗、宠物猫
- 结构对象角色:主人家
9.4 优缺点
9.5 使用场景
十.备忘录模式
10.1 概述
定义:
又叫快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,以使以后当需要时能将该对象恢复原先保存的状态。
10.2 结构
10.3 案例
10.3.1 “白箱”备忘录模式
备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。
RoleStateMemento备忘录角色
//备忘录角色类
public class RoleStatusMemento {
private int vit;
private int atk;
private int def;
public RoleStatusMemento(int vit, int atk, int def) {
this.vit = vit;
this.atk = atk;
this.def = def;
}
public int getVit() {
return vit;
}
public int getDef() {
return def;
}
public int getAtk() {
return atk;
}
public void setVit(int vit) {
this.vit = vit;
}
public void setDef(int def) {
this.def = def;
}
public void setAtk(int atk) {
this.atk = atk;
}
}
GameRole发起人角色
//游戏角色类(发起人角色)
public class GameRole {
private int vit; //生命力
private int atk; //攻击力
private int def; //防御力
//初始化内部状态
public void iniState(){
this.vit=100;
this.atk=100;
this.def=100;
}
//战斗
public void fight(){
this.vit=0;
this.atk=0;
this.def=0;
}
//保存角色状态功能
public RoleStatusMemento saveState(){
return new RoleStatusMemento(vit, atk, def);
}
//恢复角色状态
public void recoverState(RoleStatusMemento memento){
//将备忘录对象中存储的状态赋值给当前对象的成员
this.vit=memento.getVit();
this.atk=memento.getAtk();
this.def=memento.getDef();
}
//展示状态功能
public void stateDisplay(){
System.out.println("角色生命力:"+getVit());
System.out.println("角色攻击力:"+getAtk());
System.out.println("角色防御力:"+getDef());
}
public int getAtk() {
return atk;
}
public int getDef() {
return def;
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public void setAtk(int atk) {
this.atk = atk;
}
public void setDef(int def) {
this.def = def;
}
}
RoleStateCaretaker管理人角色
//备忘录对象管理角色
public class RoleStateCaretaker {
//声明备忘录类型的变量
private RoleStatusMemento roleStatusMemento;
public RoleStatusMemento getRoleStatusMemento() {
return roleStatusMemento;
}
public void setRoleStatusMemento(RoleStatusMemento roleStatusMemento) {
this.roleStatusMemento = roleStatusMemento;
}
}
Client测试类
public class Client {
public static void main(String[] args) {
System.out.println("--------------------大战boss前----------------");
//创建游戏角色对象
GameRole gameRole=new GameRole();
gameRole.iniState();
gameRole.stateDisplay();
//将该游戏角色内部状态进行备份
//创建管理者对象
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setRoleStatusMemento(gameRole.saveState());
System.out.println("--------------------大战boss后----------------");
//损耗严重
gameRole.fight();
gameRole.stateDisplay();
System.out.println("--------------------恢复之前的状态----------------");
gameRole.recoverState(roleStateCaretaker.getRoleStatusMemento());
gameRole.stateDisplay();
}
}
分析:白箱备忘录模式是破坏封装性的。但是通过程序员自律,同样可以在一定程度上实现模式的大部分用意。
10.3.2 “黑箱”备忘录模式
备忘录角色对发起人对象提供一个宽接口,而为其他对象提供一个窄接口,在Java语言中,实现双重接口的办法就是将备忘录类设计成发起人类的成员内部类。
将RoleStateMemento设为GameRole的内部类,从而将RoleStateMemento对象封装在GameRole里面;在外面提供一个标识接口Menento给RoleStateCaretaker及其他对象使用。这样GameRole类看到的就是RoleStateMenento所有的接口,而RoleStateCaretaker及其他对象看到的仅仅是标识接口Memento所暴露出来的接口,从而维护了封装性。
GameRole类
//游戏角色类(发起人角色)
public class GameRole {
private int vit; //生命力
private int atk; //攻击力
private int def; //防御力
//初始化内部状态
public void iniState(){
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 RoleStatusMemento(vit, atk, def);
}
//恢复角色状态
public void recoverState(Memento memento){
RoleStatusMemento role = (RoleStatusMemento) memento;
//将备忘录对象中存储的状态赋值给当前对象的成员
this.vit=role.getVit();
this.atk=role.getAtk();
this.def=role.getDef();
}
//展示状态功能
public void stateDisplay(){
System.out.println("角色生命力:"+getVit());
System.out.println("角色攻击力:"+getAtk());
System.out.println("角色防御力:"+getDef());
}
public int getAtk() {
return atk;
}
public int getDef() {
return def;
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public void setAtk(int atk) {
this.atk = atk;
}
public void setDef(int def) {
this.def = def;
}
private class RoleStatusMemento implements Memento{
private int vit; //生命力
private int atk; //攻击力
private int def; //防御力
public RoleStatusMemento() {
}
public RoleStatusMemento(int vit, int def, int atk) {
this.vit = vit;
this.def = def;
this.atk = atk;
}
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类
//备忘录接口,对外提供窄接口
public interface Memento {
}
RoleStateCaretaker类
//备忘录对象管理角色
public class RoleStateCaretaker {
//声明备忘录类型的变量
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
Client测试类
public class Client {
public static void main(String[] args) {
System.out.println("--------------------大战boss前----------------");
//创建游戏角色对象
GameRole gameRole=new GameRole();
gameRole.iniState();
gameRole.stateDisplay();
//将该游戏角色内部状态进行备份
//创建管理者对象
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();
}
}
10.4 优缺点
10.5 使用场景
十一.解释器模式
11.1 概述
定义:
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器所有该标识来解释语言中的句子。
11.2 结构
11.3 案例
【例】设计实现加减法的软件
AbstractExpresstion
//抽象表达式类
public abstract class AbstractExpresstion {
public abstract int interpret(Context context);
}
Context
//环境角色类
public class Context {
//定义一个map集合,同来存储变量对应的值
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);
}
}
Minus
public class Minus extends AbstractExpresstion{
//减号左边的表达式
private AbstractExpresstion left;
//减号右边的表达式
private AbstractExpresstion right;
public Minus(AbstractExpresstion left, AbstractExpresstion right) {
this.left = left;
this.right = right;
}
public int interpret(Context context) {
//将左边表达式的结果进行相减
return left.interpret(context)-right.interpret(context);
}
public String toString() {
return "("+left.toString()+"-"+right.toString()+")";
}
}
Plus
public class Plus extends AbstractExpresstion{
//加号左边的表达式
private AbstractExpresstion left;
//加号右边的表达式
private AbstractExpresstion right;
public Plus(AbstractExpresstion left, AbstractExpresstion right) {
this.left = left;
this.right = right;
}
public int interpret(Context context) {
//将左边表达式的结果进行相加
return left.interpret(context)+right.interpret(context);
}
public String toString() {
return "("+left.toString()+"+"+right.toString()+")";
}
}
Variable
//变量类(封装变量)
public class Variable extends AbstractExpresstion{
//声明存储变量名的成员变量
private String name;
public Variable(String name) {
this.name = name;
}
public int interpret(Context context) {
//返回变量的值
return context.getValue(this);
}
public String toString(){return name;}
}
Client
public class Client {
public static void main(String[] args) {
//创建环境对象
Context context = new Context();
//创建多个变量对象
Variable a = new Variable("a");
Variable b = new Variable("b");
Variable c = new Variable("c");
Variable d = new Variable("d");
//将变量存储到环境对象中
context.assign(a,1);
context.assign(b,2);
context.assign(c,3);
context.assign(d,4);
//获取抽象语法树
AbstractExpresstion expresstion =new Minus(a,new Plus(new Minus(b, c), d));
//解释(计算)
int result = expresstion.interpret(context);
System.out.println(expresstion + " = " + result);
}
}