設計模式---建造者模式

来源:https://www.cnblogs.com/buzuweiqi/archive/2022/09/21/16709149.html
-Advertisement-
Play Games

概要 設計模式類型:創建型 目標問題:創建對象時,參數設置的靈活性問題。(具體看案例) 接下來我們看一個需要改進的案例。 對象創建的優化 現在有個Employee類,你能預想到在開發中可能會出現的問題嗎?不一定是業務方面的問題哦。 最初版 public class Employee { privat ...


概要

  • 設計模式類型:創建型
  • 目標問題:創建對象時,參數設置的靈活性問題。(具體看案例)

接下來我們看一個需要改進的案例。

對象創建的優化

現在有個Employee類,你能預想到在開發中可能會出現的問題嗎?不一定是業務方面的問題哦。

最初版

public class Employee {
    private String name;
    private String sex;
    private int age;
    private String address; // 住址
    private String post; // 郵編
    private String company; // 公司
    private String department; // 部門
    public Employee(String name, String sex, int age,
                    String address, String post, String company,
                    String department) {
        this.name = name;
        this.sex = sex;
        if (!("男".equals(sex) || "女".equals(sex))) {
            throw new RuntimeException("輸入錯誤的性別:" + sex);
        }
        this.age = age;
        if (age <= 1 || age >= 150) {
            throw new RuntimeException("輸入錯誤的年齡:" + age);
        }
        this.address = address;
        this.post = post;
        if (!postCheck()) {
            throw new RuntimeException("地址(" + address + ")與郵編(" + post + ")不一致");
        }
        this.company = company;
        this.department = department;
    }
    private boolean postCheck() {
        if (address == null/* || ... */) { // 非空check,以及其它的check(省略),address的post與設置的post是否一致等
            return false;
        }
        return true;
    }
}

實際上在業務上並沒有過多的問題,最重要的問題就是這個類的使用非常的麻煩。
首先,構造函數只有一個,如果不增加新的構造函數的話無法靈活的傳入不同數量的參數。並且為了讓其參數的設置變得靈活,我們必須重載非常多種不一樣的構造函數,工程量巨大,且枯燥乏味。

為此,我們有了一個新的改進方案。

修改版v1

public class Employee {
    private String name;
    private String sex;
    private int age;
    private String address; // 住址
    private String post; // 郵編
    private String company; // 公司
    private String department; // 部門
    public Employee() {}

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
        if (!("男".equals(sex) || "女".equals(sex))) {
            throw new RuntimeException("輸入錯誤的性別:" + sex);
        }
    }

    public void setAge(int age) {
        this.age = age;
        if (age <= 1 || age >= 150) {
            throw new RuntimeException("輸入錯誤的年齡:" + age);
        }
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setPost(String post) {
        this.post = post;
        if (!postCheck()) {
            throw new RuntimeException("地址(" + address + ")與郵編(" + post + ")不一致");
        }
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    private boolean postCheck() {
        if (address == null/* || ... */) { // 非空check,以及其它的check(省略),address的post與設置的post是否一致等
            return false;
        }
        return true;
    }
}

改成了上述方式後確實使用起來方便不少,不想傳入的參數不調用對應的set方法就好了,並且也省去了大量構造方法的定義。但是,依舊有一個問題,我們來看看使用樣例。

public static void main(String[] args) {
    Employee e = new Employee();
    e.setPost("121-1245-1231"); // 地址(null)與郵編(121-1245-1231)不一致,報錯
}

由於設置post的時候對於address屬性做了非空判斷,所以代碼書寫時address的設置一定要在post之前,否則就會報錯。這無疑增加了項目開發的難度。

既然構造函數麻煩,set也存在一些問題。那我們如何優化Employee對象的創建呢?看下麵的樣例。

修改版v2

public class Employee {
    private String name;
    private String sex;
    private int age;
    private String address; // 住址
    private String post; // 郵編
    private String company; // 公司
    private String department; // 部門
    private Employee(Builder builder) {
        this.name = builder.name;
        this.sex = builder.sex;
        this.age = builder.age;
        this.address = builder.address;
        this.post = builder.post;
        this.company = builder.company;
        this.department = builder.department;
    };
    public static Builder Builder() {
        return new Builder();
    }
    public static class Builder {
        private String name;
        private String sex;
        private int age;
        private String address; // 住址
        private String post; // 郵編
        private String company; // 公司
        private String department; // 部門

        public Builder name(String name) {
            this.name = name;
            return this;
        }
        public Builder sex(String sex) {
            this.sex = sex;
            return this;
        }
        public Builder age(int age) {
            this.age = age;
            return this;
        }
        public Builder address(String address) {
            this.address = address;
            return this;
        }
        public Builder post(String post) {
            this.post = post;
            return this;
        }
        public Builder company(String company) {
            this.company = company;
            return this;
        }
        public Builder department(String department) {
            this.department = department;
            return this;
        }
        public Employee build() {
            if (!("男".equals(sex) || "女".equals(sex))) {
                throw new RuntimeException("輸入錯誤的性別:" + sex);
            }
            if (age <= 1 || age >= 150) {
                throw new RuntimeException("輸入錯誤的年齡:" + age);
            }
            if (!postCheck()) {
                throw new RuntimeException("地址(" + address + ")與郵編(" + post + ")不一致");
            }
            return new Employee(this);
        }
        private boolean postCheck() {
            if (address == null/* || ... */) { // 非空check,以及其它的check(省略),address的post與設置的post是否一致等
                return false;
            }
            return true;
        }
    }
}

使用建造者模式優化對象的創建。客戶端中對象的創建不再使用new關鍵字,不需要定義數量繁多的構造函數以應對複雜多變的屬性設置,並且也有著set的靈活性又不存在屬性設置順序的依賴。以下是使用樣例。

public static void main(String[] args) {
    Employee e = Employee.Builder().name("張三").sex("男").age(35)
        .post("124-1241-1352").address("江西省南昌市").build(); // 執行成功
}

流式編程的風格使得代碼清晰舒爽。

總結

優點

  1. 無需定義大量的構造方法。
  2. 既有set方法的靈活性,又消除了set可能出現的屬性固定順序設置的問題。
  3. 流式編程的風格,代碼清晰簡潔。

缺點

  1. 由於定義了靜態內部類Builder,可能會使得系統的類數量激增,影響性能。
  2. 代碼的理解難度增加。

適用場景

  1. 適用於屬性很多的類的創建。
  2. 適用於對屬性設置判斷條件複雜的類的創建。尤其是屬性設置對於其他屬性有依賴的情況。

本文來自博客園,作者:buzuweiqi,轉載請註明原文鏈接:https://www.cnblogs.com/buzuweiqi/p/16709149.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 隨著前端的範疇逐漸擴大,深度逐漸下沉,富前端必然帶來的一個問題就是性能。特別是在大型複雜項目中,重前端業務可能因為一個小小的數據依賴,導致整個頁面卡頓甚至崩潰。本文基於Quick BI(數據可視化分析平臺)歷年架構變遷中性能的排查、解決和總結出的“個性”問題,嘗試總結整個前端層面相對“共性”的問題,... ...
  • 最近,有群友問我,他們的一個作業,儘量使用少的標簽去實現這樣一個象棋佈局: 他用了 60 多個標簽,而他的同學,只用了 6 個,問我有沒有辦法儘可能的做到利用更少的標簽去完成這個佈局效果。 其實,對於一個頁面的佈局而言,標簽越少不一定是好事,我們在考慮 DOM 的消耗的同時,也需要關註代碼的可讀性, ...
  • ⚠️1.1萬長文⚠️ React源碼並非洪水猛獸,知道方法,就可以很輕易地馴服它(=^▽^=)。文章基於最新的React源碼進行調試及閱讀,將以通俗地方式解讀React ...
  • 前言 如果你第一次接觸秒殺,可能還不太理解,庫存100件就賣100件,在資料庫里減到0就好了,這有什麼麻煩的?理論上是這樣,但是具體到業務場景中就沒那麼簡單了。今天就聊聊減庫存的設計,之後以高可用方案來結束秒殺設計的全部內容。 一、秒殺中的減庫存 減庫存操作一般有如下幾個方式: 1.下單減庫存:下單 ...
  • 我的設計模式之旅。本節學習模板方法模式。從多個類包含許多相似代碼的問題中思考如何在保持演算法結構完整的情況下去除重覆代碼。介紹了模板方法模式的概念和實現方法。 ...
  • 在模板模式(Template Pattern)中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類可以按需要重寫方法實現,但調用將以抽象類中定義的方式進行。這種類型的設計模式屬於行為型模式。 ...
  • 本文的重點在於說明工作中所使用的設計模式,為了能夠更好的理解設計模式,首先簡單介紹一下業務場景。使用設計模式,可以簡化代碼、提高擴展性、可維護性和復用性。有哪些設計模式,這裡就不再介紹了,網上很多,本文只介紹所用到設計模式。 ...
  • 大部分高級編程語言雖然語法不同,編譯器不同,學習它們的小哥哥小姐姐們不同,但有一點卻是出奇地一致:編程邏輯! 有些剛入行或剛入門的童鞋可能連編程是啥意思都沒弄懂,一下子又來了個「邏輯」,那是什麼?這裡說的邏輯,廣義上指的是抽象思維能力,也就是能思考那些客觀世界不存在的東西的能力。狹義上來說,就是明確 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...