序文
誰もが開発中にクソ マウンテン コードに遭遇したことがあると思います。これらのクソ マウンテン コードは通常、複雑で巨大な if-else によって引き起こされます。ステート モードは、クソ マウンテン コードを最適化するための優れた設計パターンです。この記事では、ビジネス シナリオの 2 つの例を使用して、状態パターンを使用して Shishan コードを保存する方法を説明します。
目次
1. オンラインショッピングのビジネスシナリオ
1.1. 要件
次の要件を持つオンライン ショッピング ビジネス シナリオを想定してみましょう。
-
支払い→再発送→受け取りという流れになりますが、納品後の支払い、受け取り後の配送と支払いは不可となります。
-
支払い後の支払いの繰り返し、配送後の配送の繰り返し、受け取り後の配送の繰り返しはできません
1.2. if else の実装
ここでは Order クラスを設計し、状態を表すために int 型の状態を使用します。もちろん、状態を表すために列挙型クラスを使用する方が標準化されています。これは便宜上のものです。
public class Order {
//1 未付款
//2 已付款
//3 未发货
//4 已发货
//5 未收货
//6 已收货
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
受信メソッドを例にすると、ビジネス ロジックは次のように実装されます。
public void receive(Order order){
if(order.getState()==2){
if(order.getState()==4){
if(order.getState()==5){
System.out.println("收货成功");
}else{
System.out.println("已收货,无法重复收货");
}
}else{
System.out.println("未发货");
}
}else{
System.out.println("未付款");
}
}
小さなクソ山のコードが形になり始めていることがわかりますが、より多くの状態とより複雑なビジネス ロジックがある場合、このクソ山のコードは基本的に読み取れなくなります。
1.3. ステートモードの実現
実際、注意深く観察すると、多くの場合、状態はエンティティの動作に関連していることがわかります。状態が導入される理由は、エンティティが異なる状態で異なる動作を示すことを期待するためです。
上記のシナリオを例に挙げると、支払い状態ではエンティティが支払い関連の機能を示すことができ、配送状態では配送関連の機能が表示でき、受け取り状態では受け取りの機能が表示できることが期待されます。商品....
したがって、ステータスと機能を一緒にカプセル化することが完全に可能であり、それによって外部の if-else 判断の必要性がなくなり、これがいわゆるステータス モードです。
状態モードは次の一文で要約できます。
エンティティはさまざまな状態にあり、さまざまな動作をします。
効果は次のとおりです。
判定条件によってもたらされる多くの if-else 論理分岐を節約でき、コードがより簡潔で読みやすくなります。
次に、状態パターンを使用して前のコードを書き直します。
まず、エンティティクラスの動作をまとめます。実際には、支払い、配送、受け取りの 3 つのメソッドです。コードを標準化するために、動作インターフェイスを抽象化できます。もちろん、そうではありません。抽象的であることが必要です。
public interface OrderState{
void pay(Order order);
void ship(Order order);
void receive(Order order);
}
次に、システム内のステータスを要約します。注文には 3 つの次元で 6 つのステータスがあります。
支払い状況
未払い
既に支払いました
配送状況
出荷されていません
出荷済み
受け取り状況
受信していない
受け取った
つまり、国家機関は 3 つあります。
状態と動作を結合すると、次の 3 つの状態エンティティが得られます。
支払いステータスエンティティ:
public class PayState implements OrderState{
public void pay(Order order) {
System.out.println("已支付,不能再次支付!");
}
public void ship(Order order) {
order.setOrderState(new ShipState());
System.out.println("已发货!");
}
public void receive(Order order) {
System.out.println("未发货!不能收货!");
}
}
出荷ステータスエンティティ:
public class ShipState implements OrderState{
public void pay(Order order) {
System.out.println("已发货!禁止重复支付!");
}
public void ship(Order order) {
System.out.println("已经发货!禁止重复支付");
}
public void receive(Order order) {
order.setOrderState(new ReceiveState());
System.out.println("收货成功!");
}
}
受信ステータスエンティティ
public class ReceiveState implements OrderState{
public void pay(Order order) {
System.out.println("已收货,不能再次支付!");
}
public void ship(Order order) {
System.out.println("已收货,不能再次发货!");
}
public void receive(Order order) {
System.out.println("已收货,不能再次收货!");
}
}
テストコード:
public class Test {
public static void main(String[] args) {
Order order=new Order();
//初始状态未待支付
order.setOrderState(new PayState());
order.pay();
order.ship();
order.receive();
}
}
試験結果:
2. エレベーターのビジネスシナリオ
2.1. 要件
次の状態の単純なエレベーター システムを考えます。
-
停止状態(StoppedState):エレベーターが停止状態の場合、指定階への移動要求を受け付けます。
-
上昇状態 (MovingState):エレベーターが上昇状態にある場合、エレベーターは上昇中であるため移動要求に応答できません。
-
降下状態 (MovingState):エレベータが降下状態にある場合、エレベータは降下中であるため、移動要求にも応答できません。
ルール:
-
エレベーターが停止状態のときに、指定階への移動要求を受け付けて、移動状態(上りまたは下り)に切り替えることができます。
-
エレベータが上昇状態または下降状態にある場合、移動要求は受け付けられず、現在移動中である旨のメッセージが表示される。
-
エレベータは、指定された階に到達して停止状態に切り替わるまで、移動中は他の移動要求に応答できません。
上記のビジネス シナリオでは、状態パターンを使用してエレベーター システムを最適化しました。各状態 (停止状態と移動状態) は状態クラスに対応し、その状態での動作を定義します。エレベーターの状態の切り替えは、コンテキスト クラス (ElevatorStateContext) によって管理されます。コンテキスト クラスは、さまざまな状態でさまざまな動作を実行し、状態の変化に応じて切り替える役割を果たします。状態パターンを使用することで、状態切り替えロジックをさまざまな状態クラスにカプセル化し、コードをよりモジュール化して拡張可能にします。
2.2. if else の実装
class ElevatorIfElse {
private String state = "停止";
private int currentFloor = 1;
public void setState(String newState) {
state = newState;
}
public void moveToFloor(int floor) {
if (state.equals("停止")) {
System.out.println("电梯从 " + currentFloor + " 楼移动到 " + floor + " 楼");
currentFloor = floor;
} else if (state.equals("上升")) {
System.out.println("电梯正在上升,不能移动");
} else if (state.equals("下降")) {
System.out.println("电梯正在下降,不能移动");
}
}
}
public class MainIfElse {
public static void main(String[] args) {
ElevatorIfElse elevator = new ElevatorIfElse();
elevator.moveToFloor(5);
elevator.setState("上升");
elevator.moveToFloor(3);
elevator.moveToFloor(7);
elevator.setState("停止");
elevator.moveToFloor(2);
}
}
2.3. ステートモードの実現
interface ElevatorState {
void moveToFloor(ElevatorStateContext context, int floor);
}
class StoppedState implements ElevatorState {
@Override
public void moveToFloor(ElevatorStateContext context, int floor) {
System.out.println("电梯从 " + context.getCurrentFloor() + " 楼移动到 " + floor + " 楼");
context.setCurrentFloor(floor);
context.setState(new MovingState());
}
}
class MovingState implements ElevatorState {
@Override
public void moveToFloor(ElevatorStateContext context, int floor) {
System.out.println("电梯正在移动,不能移动");
}
}
class ElevatorStateContext {
private ElevatorState state;
private int currentFloor = 1;
public ElevatorStateContext() {
this.state = new StoppedState();
}
public void setState(ElevatorState state) {
this.state = state;
}
public void moveToFloor(int floor) {
state.moveToFloor(this, floor);
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
}
public class MainStatePattern {
public static void main(String[] args) {
ElevatorStateContext context = new ElevatorStateContext();
context.moveToFloor(5);
context.setState(new MovingState());
context.moveToFloor(3);
context.moveToFloor(7);
context.setState(new StoppedState());
context.moveToFloor(2);
}
}