为什么要在If-else上陈述设计模式

时间:2019-04-22 16:25:02

标签: java design-patterns

在所有地方,我发现人们都说使用状态设计模式要好得多。我想知道为什么:

  1. 在现实中的用例中,它是对if-else的改进吗?
  2. 它使代码更易于测试吗?

任何人都可以提供一个示例,其中状态模式实际上可以改善这种情况。当我可以使用if-else时,很难理解为什么要承担以下状态模式的开销。

Internet上的示例不足以说明这种模式如何解决现实世界的问题或使代码更易于维护。

4 个答案:

答案 0 :(得分:3)

我们将需要编写代码来解释事实,但首先让我们考虑一下。状态模式允许您创建流的状态,并使用这些状态来决定去向和返回的状态。好的,让我们假设您不想每次使用对象并更改其内部值时都控制该对象的当前状态。在这种情况下,您的状态可以为您自己控制,并在每次调用时将您发送到正确的位置。在处理图形时,状态模式非常有用,但我将向您展示在GoF设计模式android应用程序中看到的另一个示例。

考虑UML: enter image description here

我们很乐意实现它。

public interface AtmState {
    void withdraw(int amount);
    void refill(int amount);
}

public class Working implements AtmState {

    Atm atm;

    Working(Atm atm) {
        this.atm = atm;
    }

    public void withdraw(int amount) {

        int cashStock = atm.getCashStock();
        if(amount > cashStock) {
            /* Insufficient fund.
            * Dispense the available cash */
            amount = cashStock;
            System.out.print("Partial amount ");
        }

        System.out.println(amount + "$ is dispensed");
        int newCashStock = cashStock - amount;
        atm.setCashStock(newCashStock);
        if(newCashStock == 0) {
            atm.setState(new NoCash(atm));
        }
    }

    public void refill(int amount) {
        System.out.println(amount + "$ is loaded");
        atm.setCashStock(atm.getCashStock()+amount);
    }
}

public class NoCash implements AtmState {

    Atm atm;

    NoCash(Atm atm) {
        this.atm = atm;
    }

    public void withdraw(int amount) {
        System.out.println("Out of cash");
    }

    public void refill(int amount) {
        System.out.println(amount + "$ is loaded");
        atm.setState(new Working(atm));
        atm.setCashStock(atm.getCashStock()+amount);
    }
}

在这一点上,我们定义了两个相互交互的状态,它们“知道”何时从其自身改变为另一种状态,因此您无需创建控制器来处理何时更改对象状态,他们已经知道何时更改。现在,让我们获取Atm实现:

public class Atm implements AtmState {
    int cashStock;
    AtmState currentState;

    public Atm() {
        currentState = new NoCash(this);
    }

    public int getCashStock() {
        return cashStock;
    }

    public void setCashStock(int CashStock) {
        this.cashStock = CashStock;
    }

    public void setState(AtmState state) {
        currentState = state;
    }

    public AtmState getState() {
        return currentState;
    }

    public void withdraw(int amount) {
        currentState.withdraw(amount);
    }

    public void refill(int amount) {
        currentState.refill(amount);
    }
}

好,现在我们有一个对象的两个语句和一个Atm实现。现在我们可以分别对其进行测试,因此我们可以像针对NoCash状态那样仅针对Working状态编写测试。如您所见,它更颗粒。这里有我们的客户代码:

public class StateClient {

    public static void main(String [] args) {
        Atm atm = new Atm();
        atm.refill(100);
        atm.withdraw(50);
        atm.withdraw(30);
        atm.withdraw(30); // overdraft
        atm.withdraw(20); // overdraft
        atm.refill(50);
        atm.withdraw(50);
    }
}

输出:

100$ is loaded
50$ is dispensed
30$ is dispensed
Partial amount 20$ is dispensed
Out of cash
50$ is loaded
50$ is dispensed

请注意,我们不需要处理ATM的状态,甚至可以轻松对其进行测试。除了没有在客户端代码中写入if-else语句外,您还已经将其写入了状态本身应位于的位置,因为您的状态需要知道何时进行检查,而不是进行检查您的客户。您的客户只需为任何电话获得正确的答案。

正如我之前说的,测试这要容易得多,因为现在您可以对任何状态进行单独的小型测试。您的逻辑分布在有意义的地方,并且您的代码变得更容易理解。

希望我能为您提供帮助。

答案 1 :(得分:0)

1)和往常一样,任何一般的“更好吗?”类型问题可以是见解,也可以用“取决于”来回答。实际用例的一个示例是拥有一个单实例对象,该对象是多个其他进程或线程的控件。进程可以轮询对象的状态,并根据该状态处理其特定逻辑。

考虑一个停车库。您可能有一个状态机,该状态机在被轮询时会通知轮询过程,表明车库已满或未满,并且可能会在一天中的某个时间根据其状态从满更改为未满,或者从不满更改为满一些因素(例如预订)。然后,您需要执行其他流程来监视入站流量,出站流量,入口处的监视器,以告知潜在客户是否有停车位,停车预订系统,季节性/学期/年度通行证等。每件事都需要知道,是否与其他所有人无关,车库是否已满。

2)任何可以明确设置状态的对象都可以轻松测试。将此与模拟某些逻辑以达到要测试的状态进行比较,后者通常更容易(人为)出错。

答案 2 :(得分:0)

  

在实际用例中,它对if-else有所改进吗?

如果if-else涉及简单的业务逻辑,那么使用状态设计模式就没有意义。但是,如果您具有复杂的业务逻辑,则最好起诉状态设计模式,因为这将帮助您解耦代码,从而有助于维护。另外,如果要添加新状态,则无需去该类,只需创建一个新类,然后在运行时就可以注入它。

  

它使代码更易于测试吗?

由于状态对应于不同的类,所以它们不是硬编码的,因此您可以在运行时注入它们,这意味着可以根据测试用例对它们进行模拟。从而简化了单元测试。

答案 3 :(得分:0)

if-else-clauses的一个问题是,它们可能会变得很长,并且很难添加另一个状态,因为您必须更改许多不同类的代码。 假设您要开发一个具有主菜单,游戏循环和最终屏幕的游戏。如果没有State-pattern,则必须在代码中非常不同的位置(如update-method或draw方法中)检查程序的当前状态。当您想添加第四种状态时,例如设置屏幕,您将不得不修改许多不同类的代码,这是不理想的。

但是,使用状态模式,您可以非常优雅地解决此问题。 enter image description here

相关问题