Нам нужно будет написать код, чтобы объяснить факты, но сначала давайте рассмотрим некоторые.Шаблон состояний позволяет вам создавать состояния потока и использовать, чтобы эти состояния решали, куда идти и что возвращать.Итак, давайте предположим, что вы не хотите контролировать текущее состояние объекта каждый раз, когда используете его и изменяете его внутренние значения.В этом случае ваш штат может контролировать себя для вас и отправлять вас в нужное место всякий раз, когда вы звоните.Шаблон State очень полезен при работе с графиками, но я покажу вам еще один пример, который я видел в Android-приложении GoF Design Patterns.
Рассмотрим 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);
}
}
На данный момент мы определили два состояния, которые взаимодействуют друг с другом, они «знают», когда перейти от себя к другомусостояние, поэтому вам не нужно создавать контроллер для обработки, когда нужно изменить состояние объекта, они уже знают, когда менять.Теперь давайте получим нашу реализацию 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
Обратите внимание, что нам не нужно обрабатывать состояние нашего банкомата, и мы даже можем легко его проверить.Кроме того, вы не вписывали операторы if-else в свой клиентский код, вы уже записали его в самих состояниях , где оно должно быть , потому что вашему состоянию нужно знать, когда проверять себя, а не себе, но не вашеклиент.Вашему клиенту просто нужно получить правильный ответ на любой вызов.
Как я уже говорил, тестировать это намного проще, потому что теперь вы можете иметь отдельные и небольшие тесты для любого состояния.Ваша логика распространяется в местах, где это имеет смысл, и ваш код становится действительно легче понять.
Надеюсь, я смогу вам помочь.