一、责任链模式
1.1概述
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。
1.2结构
1.3实现
现需要开发一个请假流程控制系统。请假一天以下的假只需要小组长同意即可;请假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行。
package com.yanyu.responsibilily;
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;
}
}
package com.yanyu.responsibilily;
//处理者抽象类
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;
}
//各级领导处理请假条方法
protected abstract void handleLeave(LeaveRequest leave);
//提交请假条
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("流程结束");
}
}
}
}
package com.yanyu.responsibilily;
//小组长
public class GroupLeader extends Handler {
public GroupLeader() {
//小组长处理1-3天的请假
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("小组长审批:同意。");
}
}
package com.yanyu.responsibilily;
//部门经理
public class Manager extends Handler {
public Manager() {
//部门经理处理3-7天的请假
super(Handler.NUM_THREE, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
package com.yanyu.responsibilily;
//总经理
public class GeneralManager extends Handler {
public GeneralManager() {
//部门经理处理7天以上的请假
super(Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
客户端类
package com.yanyu.responsibilily;
public class Client {
public static void main(String[] args) {
//请假条来一张
LeaveRequest leave = new LeaveRequest("小花",5,"身体不适");
//各位领导
GroupLeader groupLeader = new GroupLeader();
Manager manager = new Manager();
GeneralManager generalManager = new GeneralManager();
groupLeader.setNextHandler(manager);//小组长的领导是部门经理
manager.setNextHandler(generalManager);//部门经理的领导是总经理
//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。
//提交申请
groupLeader.submit(leave);
}
}
1.4 优缺点
1,优点:
2,缺点:
1.5应用场景
1.6源码解析
在javaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析:
public interface Request{
}
public interface Response{
}
public interface Filter {
public void doFilter(Request req,Response res,FilterChain c);
}
模拟实现具体过滤器
public class FirstFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器1 前置处理");
// 先执行所有request再倒序执行所有response
chain.doFilter(request, response);
System.out.println("过滤器1 后置处理");
}
}
public class SecondFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器2 前置处理");
// 先执行所有request再倒序执行所有response
chain.doFilter(request, response);
System.out.println("过滤器2 后置处理");
}
}
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
// 链式调用
public FilterChain addFilter(Filter filter) {
this.filters.add(filter);
return this;
}
public void doFilter(Request request, Response response) {
if (index == filters.size()) {
return;
}
Filter filter = filters.get(index);
index++;
filter.doFilter(request, response, this);
}
}
测试类
public class Client {
public static void main(String[] args) {
Request req = null;
Response res = null ;
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
filterChain.doFilter(req,res);
}
}
二、状态模式
2.1概述
【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态,关门状态,停止状态,运行状态。每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行时状态,就不能进行开门操作,而如果电梯门是停止状态,就可以执行开门操作。
2.2结构
2.3实现
package com.yanyu.State;
//环境角色
public class Context {
//定义出所有的电梯状态
public final static OpenningState openningState = new OpenningState();//开门状态,这时候电梯只能关闭
public final static ClosingState closeingState = new ClosingState();//关闭状态,这时候电梯可以运行、停止和开门
public final static RunningState runningState = new RunningState();//运行状态,这时候电梯只能停止
public final static StoppingState stoppingState = 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();
}
}
抽象状态(State)角色
package com.yanyu.State;
//抽象状态类
public abstract class LiftState {
//定义一个环境角色,也就是封装状态的变化引起的功能变化
protected Context context;
public void setContext(Context context) {
this.context = context;
}
//电梯开门动作
public abstract void open();
//电梯关门动作
public abstract void close();
//电梯运行动作
public abstract void run();
//电梯停止动作
public abstract void stop();
}
具体状态(Concrete State)角色
package com.yanyu.State;
//开启状态
public class OpenningState extends LiftState {
//开启当然可以关闭了,我就想测试一下电梯门开关功能
@Override
public void open() {
System.out.println("电梯门开启...");
}
//关闭电梯门
@Override
public void close() {
//状态修改
super.context.setLiftState(Context.closeingState);
//动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
super.context.getLiftState().close();
}
//电梯门不能开着就跑,这里什么也不做
@Override
public void run() {
//do nothing
}
//开门状态已经是停止的了
@Override
public void stop() {
//do nothing
}
}
package com.yanyu.State;
// 关闭状态类,继承自电梯状态类
public class ClosingState extends LiftState {
@Override
// 电梯门关闭,这是关闭状态要实现的动作
public void close() {
System.out.println("电梯门关闭...");
}
// 电梯门关了再打开,逗你玩呢,那这个允许呀
@Override
public void open() {
// 设置电梯状态为开启状态
super.context.setLiftState(Context.openningState);
// 调用开启状态的open方法
super.context.open();
}
// 电梯门关了就跑,这是再正常不过了
@Override
public void run() {
// 设置电梯状态为运行状态
super.context.setLiftState(Context.runningState);
// 调用运行状态的run方法
super.context.run();
}
// 电梯门关着,我就不按楼层
@Override
public void stop() {
// 设置电梯状态为停止状态
super.context.setLiftState(Context.stoppingState);
// 调用停止状态的stop方法
super.context.stop();
}
}
package com.yanyu.State;
// 运行状态类,继承自电梯状态类
public class RunningState extends LiftState {
// 运行的时候开电梯门?你疯了!电梯不会给你开的
@Override
public void open() {
// do nothing
}
// 电梯门关闭?这是肯定了
@Override
public void close() {//虽然可以关门,但这个动作不归我执行
// do nothing
}
// 这是在运行状态下要实现的方法
@Override
public void run() {
System.out.println("电梯正在运行...");
}
// 这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
@Override
public void stop() {
// 设置电梯状态为停止状态
super.context.setLiftState(Context.stoppingState);
// 调用停止状态的stop方法
super.context.stop();
}
}
package com.yanyu.State;
// 停止状态类,继承自电梯状态类
public class StoppingState extends LiftState {
// 停止状态,开门,那是要的!
@Override
public void open() {
// 状态修改为开启状态
super.context.setLiftState(Context.openningState);
// 动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
super.context.getLiftState().open();
}
@Override
public void close() {//虽然可以关门,但这个动作不归我执行
// 状态修改为关闭状态
super.context.setLiftState(Context.closeingState);
// 动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
super.context.getLiftState().close();
}
// 停止状态再跑起来,正常的很
@Override
public void run() {
// 状态修改为运行状态
super.context.setLiftState(Context.runningState);
// 动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
super.context.getLiftState().run();
}
// 停止状态是怎么发生的呢?当然是停止方法执行了
@Override
public void stop() {
System.out.println("电梯停止了...");
}
}
客户端类
//测试类
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setLiftState(new ClosingState());
context.open();
context.close();
context.run();
context.stop();
}
}
2.4优缺点
1,优点:
2,缺点:
2.5应用场景
三、责任链模式实验
任务描述
该场景描述的是一个代检产品在流水线上检查,产品有两个属性,长度和宽度,流水线上的处理节点也有两个,即长度检验器和宽度检验器。
本关任务:用责任链模式实现产品的检测,先检测宽度(
50<width<100
合格),再检测高度(10<height<50
合格),宽度和高度都合格则产品合格,否则产品不合格。实现方式
声明处理者接口并描述请求处理方法的签名。确定客户端如何将请求数据传递给方法。 最灵活的方式是将请求转换为对象, 然后将其以参数的形式传递给处理函数;
为了在具体处理者中消除重复的样本代码, 你可以根据处理者接口创建抽象处理者基类。该类需要有一个成员变量来存储指向链上下个处理者的引用。 你可以将其设置为不可变类。 但如果你打算在运行时对链进行改变, 则需要定义一个设定方法来修改引用成员变量的值。为了使用方便, 你还可以实现处理方法的默认行为。 如果还有剩余对象, 该方法会将请求传递给下个对象。 具体处理者还能够通过调用父对象的方法来使用这一行为;
依次创建具体处理者子类并实现其处理方法。 每个处理者在接收到请求后都必须做出两个决定:是否自行处理这个请求。是否将该请求沿着链进行传递;
客户端可以自行组装链, 或者从其他对象处获得预先组装好的链。 在后一种情况下, 你必须实现工厂类以根据配置或环境设置来创建链;
客户端可以触发链中的任意处理者, 而不仅仅是第一个。 请求将通过链进行传递, 直至某个处理者拒绝继续传递, 或者请求到达链尾;
- 链中可能只有单个链接;
- 部分请求可能无法到达链尾;
- 其他请求可能直到链尾都未被处理。
编程要求
根据提示,在右侧编辑器 Begin-End 内补充 “
HeightCheckMiddleware.java
” 和 “WidthCheckMiddleware.java
” 的代码。测试说明
请求
package step1;
import java.util.HashMap;
import java.util.Map;
// 产品类,包含宽度和高度属性
public class Product {
private Middleware middleware; // 中间件对象
private int width; // 宽度
private int height; // 高度
// 构造方法,初始化宽度和高度
public Product(int width,int height) {
this.width =width;
this.height = height;
}
// 设置中间件对象
public void setMiddleware(Middleware middleware) {
this.middleware = middleware;
}
// 获取高度
public int getHeight() {
return height;
}
// 获取宽度
public int getWidth() {
return width;
}
// 执行产品检验,调用中间件的check方法进行检验
public boolean doProcess() {
if (middleware.check(width,height)) {
System.out.println("产品最终检验合格!");
return true;
}
System.out.println("产品最终检验不合格!");
return false;
}
}
抽象处理者(Handler)角色
package step1;
public abstract class Middleware {
private Middleware next;
/* Builds chains of middleware objects.*/
public static Middleware link(Middleware first, Middleware... chain) {
Middleware head = first;
for (Middleware nextInChain: chain) {
head.next = nextInChain;
head = nextInChain;
}
return first;
}
/**
* 在具体的节点中去实现check.
*/
public abstract boolean check(int width, int height);
/**
* Runs check on the next object in chain or ends traversing if we're in
* last object in chain.
*/
protected boolean checkNext(int width, int height) {
if (next == null) {
return true;
}
return next.check(width, height);
}
}
具体处理者(Handler)角色
package step1;
public class HeightCheckMiddleware extends Middleware{
public boolean check(int width, int height) {
/*产品高度检验通过 产品高度未检验通过*/
/********** Begin *********/
if (height > 10 && height < 50) {
System.out.println("产品高度检验通过");
return checkNext(width, height);
} else {
System.out.println("产品高度未检验通过");
return false;
}
/********** End *********/
}
}
package step1;
public class WidthCheckMiddleware extends Middleware {
public boolean check(int width, int height) {
/*产品宽度未检验通过 产品宽度检验通过*/
/********** Begin *********/
if (width > 50 && width < 100) {
System.out.println("产品宽度检验通过");
return checkNext(width, height);
} else {
System.out.println("产品宽度未检验通过");
return false;
}
/********** End *********/
}
}
客户端类
package step1;
import java.io.IOException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
// 创建一个扫描器对象,用于读取用户输入的宽度和高度
Scanner scanner = new Scanner(System.in);
int width = scanner.nextInt(); // 读取用户输入的宽度
int height = scanner.nextInt(); // 读取用户输入的高度
Product product = new Product(width,height); // 创建一个产品对象,传入宽度和高度
// 构建检测链
Middleware middleware = Middleware.link(
new WidthCheckMiddleware(), // 创建一个宽度检查中间件对象
new HeightCheckMiddleware() // 创建一个高度检查中间件对象
);
// 将检测链的首节点设置为产品对象的中间件
product.setMiddleware(middleware);
// 启动产品对象的检测链
product.doProcess();
}
}
四、状态模式实验
任务描述
刚加入的顾客被归入普通会员,要求填入姓名;当顾客积分大于等于500时自动升级为黄金会员,下次享受黄金会员待遇;当积分大于等于2000时自动升级为 VIP 会员,下次起享受 VIP 会员待遇。注意:会员升级过程不能跳级。
实现方式
确定哪些类是上下文。 它可能是包含依赖于状态的代码的已有类; 如果特定于状态的代码分散在多个类中, 那么它可能是一个新的类;
声明状态接口。 虽然你可能会需要完全复制上下文中声明的所有方法, 但最好是仅把关注点放在那些可能包含特定于状态的行为的方法上;
为每个实际状态创建一个继承于状态接口的类。 然后检查上下文中的方法并将与特定状态相关的所有代码抽取到新建的类中。在将代码移动到状态类的过程中, 你可能会发现它依赖于上下文中的一些私有成员。 你可以采用以下几种变通方式:
编程要求
根据提示,在右侧编辑器 Begin-End 内补全代码,需要补充代码的文件如下:
测试说明
输入第一行表示顾客姓名,第二行给出一个正整数
n(n⩽10)
表示消费次数。随后n
行,每行给出1个实数(消费金额)。输出n
行结果,格式为XX 本次消费金额为 XX,折扣后为 XX
测试输入:
张三
3
612.0
1621.0
100.0
预期输出:张三注册成功
普通会员本次消费金额:612.0,折扣后:612.0,当前积分:612
黄金会员本次消费金额:1621.0,折扣后:1539.9,当前积分:2151
VIP会员本次消费金额:100.0,折扣后:85.0,当前积分:2236
环境(Context)角色
package step1;
public class clubAccount {
private String name; // 姓名
private AbstractState state; // 当前状态
public clubAccount(String name) {
this.name = name;
// 初始化账户状态为普通状态
this.state = new CommonState(this);
System.out.println(this.name + "注册成功!");
}
// 设置账户状态
public void setState(AbstractState state) {
this.state = state;
}
// 消费
public void Consume(double money) {
/********** Begin *********/
// 调用当前状态的消费方法
state.Consume(money);
/********** End *********/
}
}
这里的
new CommonState(this)
表示创建一个新的状态对象,并将当前对象(即this
)作为参数传递给CommonState
的构造函数
抽象状态(State)角色
package step1;
public abstract class AbstractState {
protected clubAccount account;//账户
protected double discount;//折扣比例
protected int userPoints;//积分
protected String stateName;//状态名
public void Consume(double money)
{
/********** Begin *********/
userPoints += (int)(money*discount);
checkState();
/********** End *********/
///现金消费
System.out.println(stateName+"本次消费金额:"+money+",折扣后:"+String.format("%.1f",money*discount)+",当前积分:"+userPoints);
}
///若有积分抵现金或领取礼物则需要修改checkState原型,请自由扩展积分消费函数
public abstract void checkState();
}
具体状态(State)角色
package step1;
// 定义一个名为CommonState的类,继承自AbstractState类
public class CommonState extends AbstractState {
// 构造方法1:接收一个AbstractState类型的参数state
public CommonState(AbstractState state) {
// 将传入的state对象的userPoints属性赋值给当前对象的userPoints属性
this.userPoints = state.userPoints;
// 设置当前对象的状态名称为"普通会员"
this.stateName = "普通会员";
// 将传入的state对象的account属性赋值给当前对象的account属性
this.account = state.account;
// 设置当前对象的折扣为1
this.discount = 1;
}
// 构造方法2:接收一个clubAccount类型的参数account
public CommonState(clubAccount account) {
// 将传入的account对象的account属性赋值给当前对象的account属性
this.account = account;
// 设置当前对象的用户积分为0
this.userPoints = 0;
// 设置当前对象的状态名称为"普通会员"
this.stateName = "普通会员";
// 设置当前对象的折扣为1
this.discount = 1;
}
// 重写checkState方法
@Override
public void checkState() {
/********** Begin *********/
// 如果用户积分大于等于2000,将账户状态设置为VIPState
if (userPoints >= 2000) {
account.setState(new VIPState(this));
}
// 如果用户积分大于等于500,将账户状态设置为GoldState
else if (userPoints >= 500) {
account.setState(new GoldState(this));
}
/********** End *********/
}
}
package step1;
public class GoldState extends AbstractState{
public GoldState(AbstractState state)
{
this.userPoints=state.userPoints;
this.stateName="黄金会员";
this.account= state.account;
this.discount=0.95;
}
@Override
public void checkState() {
/********** Begin *********/
if (userPoints >= 2000) {
account.setState(new VIPState(this));
}
/********** End *********/
}
}
package step1;
public class VIPState extends AbstractState{
public VIPState(AbstractState state)
{
this.userPoints=state.userPoints;
this.stateName="VIP会员";
this.account= state.account;
this.discount=0.85;
}
@Override
public void checkState() {
}
}
客户端类
package step1;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
// 创建一个扫描器对象,用于读取用户输入
Scanner scanner = new Scanner(System.in);
// 读取用户输入的姓名
String name = scanner.next();
// 根据姓名创建一个俱乐部账户对象
clubAccount account = new clubAccount(name);
// 读取用户输入的消费次数
int n = scanner.nextInt();
// 定义一个变量用于存储每次消费的金额
float money;
// 循环n次,每次读取用户输入的消费金额并调用Consume方法进行消费操作
for (int i = 0; i < n; i++) {
money = scanner.nextFloat();
account.Consume(money);
}
}
}
原文地址:https://blog.csdn.net/qq_62377885/article/details/134616605
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_18721.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!