最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java設計模式之狀態(tài)模式詳解

 更新時間:2023年05月12日 10:38:12   作者:蜀山劍客李沐白  
Java?中的狀態(tài)模式(State?Pattern)是一種行為型設計模式,它允許對象在內(nèi)部狀態(tài)發(fā)生改變時改變其行為,本文將詳細介紹?Java?中的狀態(tài)模式,我們將從狀態(tài)模式的概述、結構與實現(xiàn)、優(yōu)缺點、適用場景等方面進行講解,需要的朋友可以參考下

1. 狀態(tài)模式的概述

狀態(tài)模式是一種通過將對象的狀態(tài)轉換邏輯分布到狀態(tài)對象中來實現(xiàn)狀態(tài)轉換的設計模式。它將對象的行為與對應的狀態(tài)分離,使得在修改對象狀態(tài)時,不需要修改對象的行為方法。同時,狀態(tài)模式可以通過將狀態(tài)的轉換邏輯包含在各個狀態(tài)類中來簡化代碼,避免出現(xiàn)大量的條件判斷語句,從而提高代碼的可讀性和可維護性。

根據(jù) GoF 的定義,狀態(tài)模式的三個核心角色分別是:

  • 環(huán)境(Context):它定義了客戶端所感興趣的接口,并維護一個當前狀態(tài),在具體狀態(tài)類中實現(xiàn)該接口的各個具體操作。
  • 抽象狀態(tài)(State):它定義了一個接口,用于封裝環(huán)境對象中不同狀態(tài)對應的行為。
  • 具體狀態(tài)(Concrete State):它實現(xiàn)了抽象狀態(tài)接口,封裝了不同狀態(tài)下對環(huán)境對象的響應行為。

2. 狀態(tài)模式的結構與實現(xiàn)

在 Java 中,狀態(tài)模式的實現(xiàn)方法比較簡單,通??梢园凑找韵虏襟E進行:

  • 定義抽象狀態(tài)接口(State),它包含了具體狀態(tài)所對應的操作方法;
  • 定義具體狀態(tài)類(ConcreteState1、ConcreteState2等),它們實現(xiàn)了抽象狀態(tài)接口,封裝了具體的狀態(tài)行為;
  • 定義環(huán)境類(Context),它包含了當前狀態(tài)以及對外提供的操作接口;
  • 在環(huán)境類中,使用一個State類型的變量來表示當前狀態(tài),并在具體操作中調(diào)用該狀態(tài)的方法;
  • 當狀態(tài)發(fā)生改變時,修改環(huán)境對象的狀態(tài)即可。

下面是 Java 中狀態(tài)模式的一個簡單實現(xiàn):

// 定義抽象狀態(tài)接口
interface State {
    void handle();
}

// 定義具體狀態(tài)類
class ConcreteState1 implements State {
    @Override
    public void handle() {
        System.out.println("當前狀態(tài)為 State1.");
    }
}

class ConcreteState2 implements State {
    @Override
    public void handle() {
        System.out.println("當前狀態(tài)為 State2.");
    }
}

// 定義環(huán)境類
class Context {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void request() {
        state.handle();
    }
}

// 示例程序
public class StatePatternDemo {
    public static void main(String[] args) {
        // 創(chuàng)建狀態(tài)對象
        State state1 = new ConcreteState1();
        State state2 = new ConcreteState2();

        // 創(chuàng)建環(huán)境對象
        Context context = new Context();
        context.setState(state1);
        context.request();

        context.setState(state2);
        context.request();
    }
}

在上述代碼中,我們首先定義了抽象狀態(tài)接口State和兩個具體狀態(tài)類ConcreteState1、ConcreteState2,它們分別實現(xiàn)了State接口。然后,我們定義了一個包含狀態(tài)切換邏輯的環(huán)境類Context,其中,使用狀態(tài)對象來表示當前的狀態(tài),并在request方法中調(diào)用當前狀態(tài)的handle方法。最后,我們創(chuàng)建一個示例程序,調(diào)用context的setState方法來改變狀態(tài),并觀察其輸出。

3. 狀態(tài)模式的優(yōu)缺點

狀態(tài)模式具有如下優(yōu)點:

  • 結構清晰、封裝性好:將狀態(tài)的轉換邏輯分布到獨立的狀態(tài)類中,使得狀態(tài)之間的耦合度降低,并且可以將狀態(tài)的行為封裝在狀態(tài)類中,提高了系統(tǒng)的可維護性和可讀性。
  • 擴展性好:對于新的狀態(tài),只需要創(chuàng)建一個具體狀態(tài)類即可,同時也可以很方便地增加新的狀態(tài)轉換。
  • 易于維護和調(diào)試:狀態(tài)模式將各個狀態(tài)進行了封裝,每個狀態(tài)對象都只關注自身的行為,使得代碼易于維護和調(diào)試。

但是狀態(tài)模式也存在一些缺點:

  • 狀態(tài)模式會導致系統(tǒng)類和對象的個數(shù)增加:狀態(tài)模式將每個狀態(tài)都封裝成了獨立的對象,因此會增加系統(tǒng)的復雜度和實現(xiàn)難度。
  • 狀態(tài)模式的使用條件較為苛刻:由于狀態(tài)模式要求將狀態(tài)轉換邏輯包含在具體狀態(tài)類中,因此只適合“狀態(tài)不多”且“狀態(tài)轉換比較少”的情況,否則會導致系統(tǒng)的維護和擴展變得困難。

4. 狀態(tài)模式的適用場景

狀態(tài)模式通常適用于以下情形:

  • 行為隨狀態(tài)改變而改變的場景:在狀態(tài)模式中,行為是由狀態(tài)決定的,因此當一個對象狀態(tài)改變時,它所對應的行為也隨之改變。
  • 條件、分支語句多的場景:如果使用傳統(tǒng)的if/else語句實現(xiàn)狀態(tài)轉換邏輯,通常會出現(xiàn)大量的條件語句,從而導致代碼復雜度的提高,而狀態(tài)模式可以很好地解決這個問題。

具體來說,狀態(tài)模式通常適用于以下場景:

  • 對象的行為取決于它的狀態(tài),并且它必須在運行時刻根據(jù)狀態(tài)改變它的行為;
  • 某個操作有多個狀態(tài),且這些狀態(tài)之間可以相互轉換;
  • 在不同狀態(tài)下執(zhí)行的操作有大量重復代碼時,可以將該重復代碼封裝在具體狀態(tài)類中,從而提高代碼的重用性和可維護性。

5. 示例程序的設計與實現(xiàn)

下面我們將使用一個簡單示例來說明狀態(tài)模式的具體實現(xiàn)方法。假設我們正在開發(fā)一個多線程下載器程序,該程序可以同時下載多個文件,并且可以監(jiān)控每個文件的下載進度,當某個文件下載完成后,該程序需要自動關閉該文件的下載線程并向用戶發(fā)送下載完成的提示信息。

為了實現(xiàn)上述功能,我們可以使用狀態(tài)模式對下載器程序進行重構,具體設計如下:

  • 定義抽象狀態(tài)類,并聲明抽象的 download 方法,用于封裝不同狀態(tài)下的共性操作。
  • 定義具體狀態(tài)類,并實現(xiàn) download 方法,用于完成具體的狀態(tài)操作邏輯。
  • 在 ConcreteState 類中,定義一個靜態(tài)變量來表示當前狀態(tài),在 download 方法中根據(jù)下載狀態(tài)進行狀態(tài)轉換。
  • 在 Context 類中,維護一個當前狀態(tài),并將 download 方法委托給當前狀態(tài)對象來執(zhí)行。

接下來我們來看一下示例程序的具體實現(xiàn)。在本示例程序中,我們使用了 Java 中的線程池和 FutureTask,實現(xiàn)了對多個文件的同時下載。需要注意的是,由于本文篇幅較長,為了讓代碼更加清晰,我們將代碼拆分成了多個類來實現(xiàn)相應的功能。

(1)抽象狀態(tài)類

public abstract class DownloadState {
    protected DownloadContext context;

    public void setContext(DownloadContext context) {
        this.context = context;
    }

    public abstract void download(String url, String filePath);
}

在上述代碼中,我們定義了一個抽象狀態(tài)類 DownloadState,它包含了一個 DownloadContext 對象,以及一個 download 方法,用于封裝不同狀態(tài)下的下載操作。需要注意的是,該抽象方法不包含具體的下載邏輯,具體的下載邏輯需要在具體狀態(tài)類中進行實現(xiàn)。

(2)具體狀態(tài)類

public class DownloadingState extends DownloadState {
    private FutureTask<Integer> futureTask;

    @Override
    public void download(String url, String filePath) {
        System.out.println("開始下載文件:" + filePath);

        // 開始下載
        DownloadTask task = new DownloadTask(url, filePath);
        futureTask = new FutureTask<>(task);
        ThreadPool.getInstance().execute(futureTask);

        // 狀態(tài)轉換
        try {
            int result = futureTask.get();
            if (result == 0) {
                context.setState(new FinishedState());
            } else {
                context.setState(new ErrorState());
            }
        } catch (Exception e) {
            e.printStackTrace();
            context.setState(new ErrorState());
        }
    }
}

public class FinishedState extends DownloadState {
    @Override
    public void download(String url, String filePath) {
        System.out.println("文件已下載完成,無需重復下載!");
        context.closeDownloadThread(filePath);
    }
}

public class ErrorState extends DownloadState {
    @Override
    public void download(String url, String filePath) {
        System.out.println("下載文件出錯,無法繼續(xù)下載!");
        context.closeDownloadThread(filePath);
    }
}

在上述代碼中,我們定義了三個具體狀態(tài)類:DownloadingState、FinishedState 和 ErrorState,它們分別代表下載中、下載完成和下載出錯三種狀態(tài)。其中,我們使用了線程池和 FutureTask 來實現(xiàn)下載操作,并根據(jù)下載結果進行狀態(tài)轉換(對于下載成功的情況,我們轉換到FinishedState;對于下載出錯的情況,我們轉換到ErrorState)。

需要注意的是,由于下載完成或下載出錯后都需要關閉下載線程,因此我們在FinishedState和ErrorState中都調(diào)用了context對象的closeDownloadThread方法來實現(xiàn)該功能。

(3)環(huán)境類

public class DownloadContext {
    private DownloadState currentState;
    private Map<String, FutureTask<Integer>> taskMap;

    public DownloadContext() {
        this.currentState = new FinishedState();
        this.taskMap = new HashMap<>();
      }

      public void setState(DownloadState state) {
        this.currentState = state;
        this.currentState.setContext(this);
      }

      public void download(String url, String filePath) {
        FutureTask<Integer> task = this.taskMap.get(filePath);

        if (task == null || task.isDone() || task.isCancelled()) {
          this.taskMap.remove(filePath);
          this.currentState.download(url, filePath);
        } else {
          System.out.println("文件 " + filePath + " 正在下載中,無需重復下載!");
        }
      }

      public void closeDownloadThread(String filePath) {
        FutureTask<Integer> task = this.taskMap.get(filePath);

        if (task != null) {
          task.cancel(true);
          this.taskMap.remove(filePath);
          System.out.println("已關閉文件 " + filePath + " 的下載線程。");
        }
      }
}

在上述代碼中,我們定義了一個 DownloadContext 類,它包含了當前狀態(tài)以及 download 和 closeDownloadThread 方法。

在 download 方法中,我們首先檢查是否存在正在下載的任務(即 task 對象是否存在且未完成),如果不存在,則將當前狀態(tài)轉換為下載中狀態(tài),并啟動下載任務;否則輸出提示信息,防止重復下載。

在 closeDownloadThread 方法中,我們將傳入的 filePath 對應的下載任務取消,并從 taskMap 中移除該任務,同時輸出提示信息。

(4)線程池類

public class ThreadPool {
    private ExecutorService executor;

    private ThreadPool() {
        this.executor = Executors.newFixedThreadPool(5);
    }

    private static class Singleton {
        private static final ThreadPool INSTANCE = new ThreadPool();
    }

    public static ThreadPool getInstance() {
        return Singleton.INSTANCE;
    }

    public void execute(Runnable task) {
        this.executor.execute(task);
    }
}

在上述代碼中,我們定義了一個 ThreadPool 類,它包含了一個靜態(tài)的 ExecutorService 對象 executor,并封裝了一個 execute 方法用于提交任務到線程池中。

需要注意的是,由于我們要將ThreadPool類設計為單例模式,因此我們在該類中定義了一個私有的靜態(tài)內(nèi)部類Singleton,用于實現(xiàn)懶漢式單例模式。這樣可以保證線程池中只有一個實例對象,并且線程安全。

(5)示例程序

public class Main {
    public static void main(String[] args) {
        DownloadContext context = new DownloadContext();

        String url1 = "https://cdn.pixabay.com/photo/2018/10/30/16/06/water-lily-3784022__340.jpg";
        String filePath1 = "water-lily.jpg";

        String url2 = "https://cdn.pixabay.com/photo/2020/07/14/13/10/excursion-5407227__340.jpg";
        String filePath2 = "excursion.jpg";

        context.download(url1, filePath1);
        context.download(url2, filePath2);

        System.out.println("------------------------------------");

        context.download(url1, filePath1);
        context.download(url2, filePath2);
    }
}

在上述代碼中,我們創(chuàng)建了一個 DownloadContext 對象,并分別下載了兩個文件。需要注意的是,在第二次下載同一個文件時,系統(tǒng)會輸出提示信息“文件正在下載中,無需重復下載!”。

運行該程序,我們可以看到如下輸出結果:

開始下載文件:water-lily.jpg
開始下載文件:excursion.jpg
------------------------------------
文件正在下載中,無需重復下載!
文件正在下載中,無需重復下載!

從輸出結果中我們可以看出,根據(jù)不同的狀態(tài),下載器程序完成了不同的操作,并且順利地將多線程下載操作與狀態(tài)轉換功能封裝在了不同的狀態(tài)類中。

以上就是Java設計模式之狀態(tài)模式詳解的詳細內(nèi)容,更多關于Java狀態(tài)模式的資料請關注腳本之家其它相關文章!

相關文章

  • SpringSecurity request過濾問題示例小結

    SpringSecurity request過濾問題示例小結

    這篇文章主要介紹了SpringSecurity request過濾問題示例小結,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-02-02
  • spring如何快速穩(wěn)定解決循環(huán)依賴問題

    spring如何快速穩(wěn)定解決循環(huán)依賴問題

    這篇文章主要介紹了spring如何快速穩(wěn)定解決循環(huán)依賴問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • SpringMvc使用GoogleKaptcha生成驗證碼

    SpringMvc使用GoogleKaptcha生成驗證碼

    這篇文章主要為大家詳細介紹了SpringMvc項目中使用GoogleKaptcha 生成驗證碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Java中結束循環(huán)的方法

    Java中結束循環(huán)的方法

    這篇文章主要介紹了Java中結束循環(huán)的方法,文中有段代碼在return,結束了整個main方法,即使輸出hello world的語句位于循環(huán)體外,也不會被執(zhí)行,對java結束循環(huán)方法感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • Java?SpringBoot?中的操作事務

    Java?SpringBoot?中的操作事務

    這篇文章主要介紹了Java?SpringBoot?中的操作事務,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 一文讓你徹底學會Java左移、右移操作

    一文讓你徹底學會Java左移、右移操作

    這篇文章主要介紹了了Java中的位運算符,包括左移(<<)、右移(>>)和無符號右移(>>>),左移將數(shù)字的二進制位向左移動,相當于乘以2的n次方;右移將數(shù)字的二進制位向右移動,保留符號位,相當于除以2的n次方,文中介紹的非常詳細,需要的朋友可以參考下
    2025-02-02
  • Java青蛙跳臺階問題的解決思路與代碼

    Java青蛙跳臺階問題的解決思路與代碼

    這篇文章主要給大家介紹了關于Java青蛙跳臺階問題的解決思路與代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • IntellJ IDEA神器使用技巧(小結)

    IntellJ IDEA神器使用技巧(小結)

    這篇文章主要介紹了IntellJ IDEA神器使用技巧(小結),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • Mybatis使用update更新值為null時不生效問題解決

    Mybatis使用update更新值為null時不生效問題解決

    這篇文章主要介紹了Mybatis使用update更新值為null時不生效問題解決,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06
  • 功能強大的TraceId?搭配?ELK使用詳解

    功能強大的TraceId?搭配?ELK使用詳解

    這篇文章主要為大家介紹了功能強大的TraceId?搭配?ELK使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09

最新評論

竹山县| 丹棱县| 罗甸县| 莱西市| 铜梁县| 信阳市| 温宿县| 二手房| 黄骅市| 太仆寺旗| 广丰县| 漳平市| 安泽县| 云阳县| 读书| 商都县| 密云县| 漾濞| 连山| 武功县| 自贡市| 应城市| 西青区| 巴东县| 集安市| 广东省| 和田县| 三门县| 兴宁市| 城固县| 忻州市| 嘉定区| 保康县| 都江堰市| 印江| 清远市| 施秉县| 瓦房店市| 沙洋县| 湖南省| 织金县|