首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 設計模式實戰:Multiton 多例模式實現多語言資源管理

     編輯:Java 相關知識

從 Singleton 到 Multiton:受控實例的自然延伸

Singleton 限制全局唯一實例,但實際場景常需「有限個、帶狀態、按鍵查找」的實例集合。Multiton(多例模式) 正是此需求的標準答案:

  • 實例數量有上限(有界多例)或無上限(無界多例)
  • 類自行管理實例生命週期,對外提供靜態工廠方法
  • 每個實例擁有獨立狀態(如 Locale),按鍵(如 en_US)區分

Singleton 結構 Multiton 結構

項目背景:華爾街金融網站的 19 國語言挑戰

  • 靜態文字:交由翻譯公司產出各語言版本頁面
  • 動態文字(數據庫幣別名稱、下拉選單等):需程式動態國際化
  • 架構決策:MVC 分層,Model 純英文核心,View 層掛載多語言殼層

MVC 架構 英文核心+翻譯殼層

Locale 與 ResourceBundle 機制速覽

// 使用方式
Locale locale = new Locale("zh", "CN");
ResourceBundle bundle = ResourceBundle.getBundle("res", locale);
// 自動載入 res_zh_CN.properties
String usd = bundle.getString("USD");  // 取得 "美元"

核心實現:無界有狀態 Multiton - LingualResource

package com.javapatterns.multilingual;
import java.util.*;

public class LingualResource {
    // 單例緩存:Locale代碼 -> LingualResource實例
    private static final Map instances = new HashMap<>(19);
    private static final String BUNDLE_BASE = "res";

    // 實例狀態
    private final Locale locale;
    private final ResourceBundle bundle;

    // 私有構造:載入對應 ResourceBundle
    private LingualResource(String language, String country) {
        this.locale = new Locale(language, country);
        this.bundle = ResourceBundle.getBundle(BUNDLE_BASE, locale);
    }

    // 靜態工廠方法:獲取或創建實例
    public static synchronized LingualResource getInstance(String language, String country) {
        String key = language + "_" + country;
        if (instances.containsKey(key)) {
            return instances.get(key);
        }
        LingualResource lr = new LingualResource(language, country);
        instances.put(key, lr);
        return lr;
    }

    // 業務方法:按鍵取得本地化字串
    public String getLocaleString(String key) {
        return bundle.getString(key);
    }
}

資源文件範例

# res_en_US.properties
USD=US Dollar
JPY=Japanese Yen
EUR=Euro

# res_zh_CN.properties
USD=美元
JPY=日元
EUR=歐元

客戶端使用:JSP 頁面動態切換語言

<%-- 用戶選擇語言後,存入 Session --%>
<% 
    String lang = request.getParameter("lang");  // "en" or "zh"
    String country = request.getParameter("country"); // "US" or "CN"
    session.setAttribute("locale", new Locale(lang, country));
%>

<%-- 頁面顯示幣別下拉選單 --%>
<%
    Locale userLocale = (Locale) session.getAttribute("locale");
    LingualResource lr = LingualResource.getInstance(
        userLocale.getLanguage(), userLocale.getCountry());
%>
<select name="currency">
    <option value="USD"><%= lr.getLocaleString("USD") %></option>
    <option value="JPY"><%= lr.getLocaleString("JPY") %></option>
    <option value="EUR"><%= lr.getLocaleString("EUR") %></option>
</select>

進階話題:Java 內建格式化工具類

除了字串翻譯,數字、貨幣、百分比格式同樣需本地化:

數字格式化

NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMANY);
nf.format(1234567.89);  // "1.234.567,89" (德文格式)

貨幣格式化

NumberFormat cf = NumberFormat.getCurrencyInstance(Locale.FRANCE);
cf.format(1234567.89);  // "1 234 567,89 €" (法文格式)

百分比格式化

NumberFormat pf = NumberFormat.getPercentInstance(Locale.US);
pf.format(0.456789);  // "45.6789%" (美式)

NumberFormat 類結構 貨幣格式化 百分比格式化

模式變體與選型指南

代碼類型範例說明
語言代碼en, zh, ja, frISO 639
地區代碼US, CN, JP, FRISO 3166
Locale 代碼en_US, zh_CN, ja_JP語言_地區,對應 properties 文件後綴

分佈式環境警示

在 EJB/RMI/微服務集群中,JVM 級 Multiton 會導致每節點各自一份實例,狀態不一致風險極高。解決方案:

  • 改用分佈式緩存 存儲共享狀態
  • 或將 Multiton 降級為無狀態工具類,狀態外部化

總結

Multiton 模式以「受控實例集合」優雅解決了「按鍵區分、狀態隔離、全局訪問」的三重需求。結合 ResourceBundle 機制,我們以 50 行核心代碼構建了企業級多語言支撐框架——這正是設計模式的價值:用經典結構消解業務複雜度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
變體適用場景實現關鍵
有界 Multiton固定少量實例(如骰子雙例、連接池固定大小)靜態陣列/字段直接持有實例
無界 Multiton實例鍵動態增長(如 Locale、租戶配置)Map 緩存 + 懶加載
不可變 Multiton實例狀態創建後不變(如 ResourceBundle)final 字段,線程安全
可變 Multiton實例狀態運行時可變更需同步控制,分佈式環境慎用