介绍
状态模式定义:
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
用自己的理解解释一下,就例如人存在多种情绪一样,人类似于对象,情绪就是内部状态,人处于不同情绪时的行为可能是不一样的。如果站在程序的角度,如果我们需要根据内部状态来决定具体对象的行为逻辑,那么一种状态我们就需要加一种判断,状态彼此间过于耦合。所以状态模式将状态也抽象成对象,将状态可能导致的行为放在状态类中去实现,符合迪米特原则。
案例
在一些游戏中商人存在好感度系统,好感度达到一定程度就可以购买一些新的商品,我们可以将商人的好感度阶段看作一种状态,其中状态中变化的方法有购买商品变化,商人对话文案变化,商人好感度提升方式变化。在这里我们将商人好感度分为3个阶段,陌生,熟悉,挚友。接下来看代码实现
NPC类(对象类)
@Data
public class NPC {
AbstractOpinion opinion;
public NPC() {
this.opinion = new StrangeOpinion(this);
}
public void receiveGift(int gift){
opinion.addOpinion(gift);
}
}
好感度抽象类(状态抽象类)
public abstract class AbstractOpinion {
//npc对象
protected NPC npc;
//好感度值
protected int goodOpinion=0;
//加好感方法,我这里简单化处理,就是送礼加好感,实际中业务逻辑会更加复杂一些
public abstract void addOpinion(int gift);
//好感度阶段转换,检查好感度是否变化到超过阶段临界值,超过则进行状态变化
public abstract void changeOpinion();
//出售商品
public abstract void sold();
//对话
public abstract void talk();
}
陌生阶段好感度类
//70以下好感度为熟悉
public class FamiliarOpinion extends AbstractOpinion{
public FamiliarOpinion(AbstractOpinion abstractOpinion) {
goodOpinion=abstractOpinion.goodOpinion;
this.npc=abstractOpinion.npc;
}
@Override
public void addOpinion(int gift) {
goodOpinion+=gift;
System.out.println("熟悉阶段好感度增加"+gift);
System.out.println("当前好感度:"+goodOpinion);
changeOpinion();
}
@Override
public void changeOpinion() {
if(goodOpinion>70){
System.out.println("好感度超过70,npc现在认为你是他的挚友");
npc.setOpinion(new IntimateOpinion(this));
}
}
//这里不同好感度可能会出售不同的商品
@Override
public void sold() {
System.out.println("熟悉阶段NPC出售商品");
}
//这里不同好感度可能会有不同的对话
@Override
public void talk() {
System.out.println("熟悉阶段NPC对话");
}
}
熟悉阶段好感度
//好感度0-30为陌生阶段
public class StrangeOpinion extends AbstractOpinion{
public StrangeOpinion(NPC npc) {
goodOpinion=0;
this.npc=npc;
}
public StrangeOpinion(AbstractOpinion abstractOpinion) {
goodOpinion=abstractOpinion.goodOpinion;
this.npc=abstractOpinion.npc;
}
@Override
public void addOpinion(int gift) {
goodOpinion+=gift;
System.out.println("陌生阶段好感度增加"+gift);
System.out.println("当前好感度:"+goodOpinion);
changeOpinion();
}
@Override
public void changeOpinion() {
if(goodOpinion>30){
System.out.println("好感度超过30,npc现在认为你是熟悉的朋友");
npc.setOpinion(new FamiliarOpinion(this));
}
}
//这里不同好感度可能会出售不同的商品
@Override
public void sold() {
System.out.println("陌生阶段NPC出售商品");
}
//这里不同好感度可能会有不同的对话
@Override
public void talk() {
System.out.println("陌生阶段NPC对话");
}
}
挚友阶段
public class IntimateOpinion extends AbstractOpinion{
public IntimateOpinion(AbstractOpinion abstractOpinion) {
goodOpinion=abstractOpinion.goodOpinion;
this.npc=abstractOpinion.npc;
}
@Override
public void addOpinion(int gift) {
if(goodOpinion>=100) {
System.out.println("好感度已达上线,请不要再送礼物");
return;
}
goodOpinion+=gift;
if(goodOpinion>=100) {
goodOpinion=100;
System.out.println("好感度达到100,已达到上线");
return;
}
System.out.println("挚友阶段好感度增加"+gift);
System.out.println("当前好感度:"+goodOpinion);
changeOpinion();
}
//最高好感度不需要改变状态
@Override
public void changeOpinion() {
}
//这里不同好感度可能会出售不同的商品
@Override
public void sold() {
System.out.println("挚友阶段NPC出售商品");
}
//这里不同好感度可能会有不同的对话
@Override
public void talk() {
System.out.println("挚友阶段NPC对话");
}
}
测试
@Test
public void test()
{
NPC SaiLiYa = new NPC();
SaiLiYa.receiveGift(20);
SaiLiYa.receiveGift(20);
SaiLiYa.receiveGift(20);
SaiLiYa.receiveGift(20);
SaiLiYa.receiveGift(20);
SaiLiYa.receiveGift(20);
}
测试结果
陌生阶段好感度增加20
当前好感度:20
陌生阶段好感度增加20
当前好感度:40
好感度超过30,npc现在认为你是熟悉的朋友
熟悉阶段好感度增加20
当前好感度:60
熟悉阶段好感度增加20
当前好感度:80
好感度超过70,npc现在认为你是他的挚友
好感度达到100,已达到上线
好感度已达上线,请不要再送礼物
总结
可以看到,当一个对象的行为取决于它的状态并且状态会在程序运行中改变时适合用状态模式,其实每个状态具有的方法不一定一样,虽然本文案例是基本一样,但是其实每个状态具有的方法可以完全不一样,当然,这样就需要在状态转变时需要更加注意相应方法的调用设计。需要注意的是,状态模式的结构本身并不简单,使用时需要注意状态模式的设计。