欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 设计模式の状态策略责任链模式

设计模式の状态策略责任链模式

2025/1/3 13:09:52 来源:https://blog.csdn.net/2301_77599076/article/details/144804990  浏览:    关键词:设计模式の状态策略责任链模式

文章目录

  • 前言
  • 一、状态模式
  • 二、策略模式
  • 三、责任链模式


前言

  本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。


一、状态模式

  状态模式是一种行为设计模式,核心思想在于,使某个对象在其内部状态改变时,改变该对象的行为,使对象看起来像是改变了其类。将状态的相关行为封装到独立的状态类中,并通过在运行时切换状态对象来改变对象的行为。实现方式在于,将状态抽取成单独的类,并由上下文类统一管理。
  状态模式的结构包括以下几个主要角色:

  1. 上下文类:它维护一个当前状态的实例,并且对客户端公开其接口。
  2. 抽象状态类:定义了所有具体状态类需要实现的接口,抽取出所有状态下共有的方法。
  3. 具体状态类:实现了抽象状态类,根据自身状态的特点,有选择性第重写父类方法的逻辑。

  假设需要设计一个抽奖系统,有四种状态:

  • 不能抽奖的状态
  • 可以抽奖的状态
  • 发放奖品的状态
  • 奖品发放完成的状态

  状态流转方式如下:
在这里插入图片描述  体现在代码上,首先设计一个抽象状态接口,该接口将各种状态下可能的操作进行聚合:

/*** 状态接口* 将各种状态下可能的操作聚合成一个接口* 实现类根据各自状态可能的业务去重写其中的方法*/
public interface State {/*** 扣除积分*/void deduceMoney();/*** 抽奖* @return*/boolean raffle();/*** 发放奖品*/void dispensePrice();
}

  抽象接口具体的实现
  不能抽奖状态,在此状态下只能去做出扣减积分的操作,扣减完成积分后,状态会变更为可抽奖状态

/*** 不能抽奖的状态*/
public class NoRaffleState implements State{RaffleActivity raffleActivity;public NoRaffleState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("扣除50积分,可以抽奖");raffleActivity.setState(raffleActivity.getCanRaffleState());}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("扣除积分方能抽奖");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("不能发放奖品");}
}

  可抽奖状态,只能进行抽奖操作:

  • 未抽中奖品,重新回到不可抽奖状态
  • 抽中了奖品,流转到发送奖品状态
/*** 可以抽奖的状态*/
public class CanRaffleState implements State{RaffleActivity raffleActivity;public CanRaffleState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("已经扣除积分,可以抽奖");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("正在抽奖,请稍等");int num = new Random().nextInt(10);if (num == 0){//中奖了,发放奖品raffleActivity.setState(raffleActivity.getDispenseState());return true;}else {System.out.println("很遗憾,您没有中奖");//回到不能抽奖的状态raffleActivity.setState(raffleActivity.getNoRaffleState());return false;}}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("没中奖,不能发放奖品");}
}

  发放奖品状态,只能进行发放奖品的操作:

  • 奖品数量充足,流转到奖品发送完成状态。
  • 奖品数量不足,改变状态为不能抽奖
/*** 发放奖品的状态*/
public class DispenseState implements State{RaffleActivity raffleActivity;public DispenseState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("不能扣除积分");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("不能抽奖");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {if (raffleActivity.getCount()>0){System.out.println("恭喜中奖了");//改变状态为不能抽奖raffleActivity.setState(raffleActivity.getNoRaffleState());}else {System.out.println("很遗憾,奖品发送完了");//改变状态为奖品发送完成raffleActivity.setState(raffleActivity.getDispenseOutState());}}
}

  奖品发放完成,则不可以进行任何操作

/*** 奖品发放完成的状态*/
public class DispenseOutState implements State{RaffleActivity raffleActivity;public DispenseOutState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("奖品发送完了,请下次再参加");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("奖品发送完了,请下次再参加");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("奖品发送完了,请下次再参加");}
}

  创建一个上下文类,对状态进行统一管理,同时对状态进行初始化,并且上面的具体状态类,也聚合了上下文类的对象:

/*** 抽奖的行为*/
public class RaffleActivity {/*** 初始的状态*/State state = null;/*** 初始的数量*/int count = 0;State canRaffleState = new CanRaffleState(this);State noRaffleState = new NoRaffleState(this);State dispenseOutState = new DispenseOutState(this);State dispenseState = new DispenseState(this);public RaffleActivity(int count) {//初始状态,不能抽奖this.state = getNoRaffleState();this.count = count;}/*** 扣除积分*/public void deduceMoney(){state.deduceMoney();}/*** 抽奖*/public void raffle(){if (state.raffle()){//领取奖品state.dispensePrice();}}public State getState() {return state;}public void setState(State state) {this.state = state;}public int getCount() {int curCount = this.count;count--;return curCount;}public void setCount(int count) {this.count = count;}public State getCanRaffleState() {return canRaffleState;}public void setCanRaffleState(State canRaffleState) {this.canRaffleState = canRaffleState;}public State getNoRaffleState() {return noRaffleState;}public void setNoRaffleState(State noRaffleState) {this.noRaffleState = noRaffleState;}public State getDispenseOutState() {return dispenseOutState;}public void setDispenseOutState(State dispenseOutState) {this.dispenseOutState = dispenseOutState;}public State getDispenseState() {return dispenseState;}public void setDispenseState(State dispenseState) {this.dispenseState = dispenseState;}
}
public class Client {public static void main(String[] args) {RaffleActivity raffleActivity = new RaffleActivity(1);for (int i = 0; i < 3; i++) {//扣积分raffleActivity.deduceMoney();//抽奖raffleActivity.raffle();}}
}

小结
状态模式的优缺点
优点:

  • 遵循单一职责原则:将与状态相关的代码封装到独立类中。
  • 开闭原则:添加新状态非常方便,无需修改现有代码。
  • 消除大量条件语句:状态切换通过对象替换实现,而非复杂的条件判断。

缺点:

  • 类的数量增加:每个状态都需要创建一个类,可能导致类数量增多。
  • 状态之间的耦合:状态类之间可能需要频繁切换,会导致一定程度的耦合。

二、策略模式

  策略模式是一种行为设计模式,核心思想在于,定义了一组算法,将每个算法封装到独立的类中,使它们可以相互替换。
  策略模式通常包括以下角色:

  1. 上下文类:持有一个策略对象的引用,并且初始化具体策略。
  2. 抽象策略类:定义了所有具体策略类需要实现的接口。
  3. 具体策略类:实现抽象策略类,包含具体的算法或行为。

  假设目前有一个方法,需要根据参数中传入的不同的业务类型,执行不同业务的分派,如果使用传统方式,则会利用switch或者if-else实现,将来需要扩展的时候,需要对分支代码进行修改:

/*** 业务处理接口*/
public interface BusinessClass {/*** 处理业务*/void handleBusiness(int type);
}
public class BusinessClassImpl implements BusinessClass{/*** 处理业务* 根据传入的参数进行分发*/@Overridepublic void handleBusiness(int type) {switch (type){case 1:this.handleBusiness1();break;case 2:this.handleBusiness2();break;case 3:this.handleBusiness3();break;default:break;}}private void handleBusiness3() {System.out.println("业务3的具体逻辑");}private void handleBusiness2() {System.out.println("业务2的具体逻辑");}private void handleBusiness1() {System.out.println("业务1的具体逻辑");}
}

  使用策略模式改造,则可以抽取一个策略接口

/*** 业务策略接口*/
public interface BusinessStrategy {/*** 处理具体的业务逻辑*/void handleBusiness();
}

  将传统方式中,每个分支中的方法都抽取到一个单独的类中,实现策略接口

public class Business1 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑1");}
}
public class Business2 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑2");}
}
public class Business3 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑3");}
}

  在上下文类中,对其进行统一的管理,业务代码只需要注入上下文类,调用其中的方法即可。

public class Context {private Map<Integer, BusinessStrategy> strategyMap = new HashMap<>();/*** 初始化上下文,k业务类型 v 业务类型具体的逻辑*/public Context(){strategyMap.put(1, new Business1());strategyMap.put(2, new Business2());strategyMap.put(3, new Business3());}/*** 处理业务* 根据传入的参数进行分发*/public void handleBusiness(int type) {BusinessStrategy strategy = strategyMap.get(type);if (strategy != null) {strategy.handleBusiness();} else {System.out.println("无效的业务类型");}}
}

小结
策略模式的优缺点
优点:

  • 遵循开闭原则:添加新策略无需修改现有代码,只需扩展新策略类。
  • 消除条件语句:避免了复杂的 if-else 或 switch-case 语句。
  • 提高灵活性:客户端可以动态选择策略。

缺点:

  • 类数量增加:每种策略需要创建一个类,可能导致类的数量过多。
  • 客户端需要了解不同策略:客户端必须知道有哪些策略才能选择合适的策略。

三、责任链模式

  责任链模式是一种行为设计模式,核心目的在于,将请求的处理责任沿着一条链传递,直到有对象处理这个请求为止。责任链模式将请求的发送者和接收者解耦,且可以动态地调整链条上的处理顺序。
  责任链模式通常包含以下角色:

  1. 抽象处理者:定义了处理请求的接口,以及一个指向下一个处理者的引用。(即将自身作为属性存放在类中)
  2. 具体处理者:继承了抽象处理者,具体去实现各自处理请求的逻辑,以及无法处理时/处理完成时,应该调用的下一个处理者
  3. 客户端:创建并组装责任链,通常会将请求发送给责任链的首个处理者

  下面来看一个案例:假设某个学校,购买教材,器材,根据金额不同,需要审批的级别也不同。
  首先构建一个请求对象

public class Request {/*** 请求id*/protected int id = 0;/*** 价格*/protected int price = 0;public Request() {}public Request(int id, int price) {this.id = id;this.price = price;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}
}

  然后定义一个抽象处理者

/*** 抽象审批人*/
public abstract class Approver {/*** 审批人名称*/protected String name;/*** 持有自己的引用*/protected Approver approver;public Approver() {}public Approver(String name) {this.name = name;}public void setApprover(Approver approver) {this.approver = approver;}/*** 子类具体去实现处理请求的逻辑* @param request*/abstract void handleReq(Request request);}

  定义具体处理人,继承抽象处理人,编写自己处理的判断逻辑:

public class TeachingDirector extends Approver{public TeachingDirector(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 5000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}
public class Dean extends Approver{public Dean(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 10000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}
public class Principal extends Approver{public Principal(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 20000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}

  最后由客户端对其进行统一组装:

public class Client {public static void main(String[] args) {Request request = new Request(1, 8000);Dean dean = new Dean("院长");TeachingDirector teachingDirector = new TeachingDirector("教学主任");Principal principal = new Principal("校长");//设置下一个审批者teachingDirector.setApprover(dean);dean.setApprover(principal);principal.setApprover(teachingDirector);//8000 教学主任处理不了,交给下一级(院长)处理teachingDirector.handleReq(request);}
}

小结
责任链模式的优缺点

优点:

  • 降低耦合度:请求发送者与接收者解耦,无需关心由谁处理请求。
  • 动态灵活:可以在运行时动态调整责任链的结构。
  • 增强扩展性:新增处理者无需修改现有代码。

缺点:

  • 链条可能过长:请求可能需要经过多个处理者,性能可能受影响。
  • 调试困难:由于请求的处理流程不明确,可能导致调试复杂。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com