为什么在 If-else 上声明设计模式

Nik*_*ani 1 java design-patterns state-pattern

我到处都发现有人说使用状态设计模式比 if else 更好。我想知道为什么:

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

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

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

Rhu*_*lus 6

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

考虑 UML: 在此处输入图片说明

我们将实施它。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

此时我们已经定义了两个相互交互的状态,它们“知道”什么时候从自身改变到另一个状态,所以你不需要创建控制器来处理什么时候改变对象状态,它们已经知道了什么时候改变。现在让我们开始我们的 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

好的,现在我们有两个对象语句和一个 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

100$ is loaded
50$ is dispensed
30$ is dispensed
Partial amount 20$ is dispensed
Out of cash
50$ is loaded
50$ is dispensed
Run Code Online (Sandbox Code Playgroud)

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

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

希望我能帮到你。