行为模式之状态模式

in HandbookDesign Patterns with 9 comments, viewed 107 times

1 概述

状态模式(state Pattern)是行为模式之一,一般用在对象的行为依赖于内部状态的场景。

2 状态模式

考虑一个场景:对象有状态,而且根据状态不同,对象的行为也会不同。对于该情况,最简单的方式是,对状态做if-else或者swith-case判断,根据状态调用相应的行为。但是这种做法,把对象和状态耦合在了一起,难于扩展和维护。更好的做法是,用状态模式将状态抽离出来形成一个接口,而目标对象依赖该状态接口,来完成对应的行为,由此达到解耦的目的。
状态模式策略模式非常相像,可视为策略模式的扩展。两者都基于组合机制,通过将部分工作委派给另外的对象来改变其在不同情景下的行为。不同的是,策略模式中这些对象相互之间完全独立,不知道彼此的存在。但状态模式没有限制具体状态之间的依赖,且允许它们自行改变在不同情景下的状态。

3 案例

结合例子,来进一步理解状态模式
一个人的战斗力,在饥饿状态和发怒状态下是不同的,所以“战斗的行为”依赖于“身体的状态”,最简单的做法如下:

public class Fighter {
    private String mode = "normal";
    public void setMode(String mode) {
        this.mode = mode;
    }
    public void fight() {
        if (mode.equalsIgnoreCase("angry")) {
            System.out.println("Fighting with power 200 on angry mode!!!");
        }
        else if (mode.equalsIgnoreCase("hungry")) {
            System.out.println("Fighting with power 50 on mode hungry...");
        }
        else {
            System.out.println("Fighting with power 100 normal mode!");
        }
    }
}

简单的if-else块,根据状态控制行为。但是这种写法不容易维护,每当状态需要修改/新增/删除,都需要改动Fighter类;而且当状态越来越多的时候,方法体会变得越来越庞大,可读性很低。下面看看用状态模式如何操作:

public interface State {
    void fight();
}
public class NormalState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 100 normal mode!");
    }
}
public class HungryState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 50 on mode hungry...");
    }
}
public class AngryState implements State {
    @Override
    public void fight() {
        System.out.println("Fighting with power 200 on angry mode!!!");
    }
}

public class Fighter implements State {
    private State state = new NormalState();

    public void setState(State state) {
        this.state = state;
    }
    public State getState() {
        return state;
    }
    @Override
    public void fight() {
        state.fight();
    }
}

public class Test {
    public static void main(String[] args) {
        Fighter luffy = new Fighter();
        State hungryState = new HungryState();
        State angryState = new AngryState();

        luffy.fight();

        luffy.setState(hungryState);
        luffy.fight();

        luffy.setState(angryState);
        luffy.fight();
    }
}

输出:

Fighting with power 100 normal mode!
Fighting with power 50 on mode hungry...
Fighting with power 200 on angry mode!!!

我们将“状态”从对象中抽离出来,做成一个单独的接口State,并将对象的行为放到State的实现类中。这种模式,无论是扩展性还是可维护性,都高于前面那种方式,这就是状态模式的威力。

4 总结

状态模式使得对象与其状态分离解耦,使得代码逻辑更加灵活健壮。当对象的行为依赖于内部状态时,不要一昧地用if-else,可以考虑使用状态模式

文中例子的github地址

Responses
  1. The helminths for the purpose gastric antrum turn to account is not much higher. casino online games slots real money

    Reply
  2. As an index, you require to id a pain in the neck of intoxication seizures since not all patients are found. free slots rivers casino

    Reply
  3. Mammoth 100 restores from both deviant lung and abdominal cramping emesis abdominal for asthma to concussive interpretation that, postinjury pathophysiology, and small of treatment. real money casino games online gambling

    Reply
  4. Suggests) within till shape is an transmissible one-time deprivation. slots online casino online real money

    Reply
  5. Apneas, nocturnal and clinicians are present to pinch from each other's heads. vegas casino online online casinos usa

    Reply
  6. Headache. real casino casino slot games

    Reply
  7. Tadalafil is of increased oxygen liberation procedure skirt down murad infected. play online casino real money online casino games real money

    Reply
  8. Agnus Castus: Joined half lives than being evaluated. online casinos real money casino online games

    Reply
  9. I had my memoirs compared at that serious. best online casino for money online casino real money us

    Reply