DDD | 02-值對象拓展示例
示例拓展
金額和貨幣
創(chuàng)建一個表示金額和貨幣的值對象(AmountVO),在系統(tǒng)中統(tǒng)一處理貨幣相關(guān)的數(shù)據(jù),確保精度和一致性。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 這個AmountVO類使用BigDecimal來精確存儲金額值,避免了浮點(diǎn)運(yùn)算可能帶來的精度問題。
同時,利用Currency類來表示貨幣類型,確保了貨幣信息的標(biāo)準(zhǔn)化。
此外,重寫了equals、hashCode和toString方法以支持比較、哈希運(yùn)算和提供人性化的字符串表示。
*/
public class AmountVO {
private final BigDecimal value; // 金額值,使用BigDecimal以精確表示貨幣值
private final Currency currency; // 貨幣類型,使用Java標(biāo)準(zhǔn)庫中的Currency類
/**
* 構(gòu)造一個新的金額值對象。
*
* @param value 金額值,要求為正數(shù)
* @param currency 貨幣類型
*/
public AmountVO(BigDecimal value, Currency currency) {
if (value.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Amount value must not be negative.");
}
this.value = value;
this.currency = currency;
}
/**
* 獲取金額值。
*
* @return 金額值
*/
public BigDecimal getValue() {
return value;
}
/**
* 獲取貨幣類型。
*
* @return 貨幣類型
*/
public Currency getCurrency() {
return currency;
}
/**
* 檢查兩個AmountVO實(shí)例是否代表相同的金額(考慮貨幣)。
*
* @param obj 另一個AmountVO實(shí)例
* @return 如果金額和貨幣都相同則返回true,否則返回false
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
AmountVO amountVO = (AmountVO) obj;
return value.equals(amountVO.value) && currency.getCurrencyCode().equals(amountVO.currency.getCurrencyCode());
}
/**
* 生成基于金額和貨幣類型的哈希碼。
*
* @return 哈希碼
*/
@Override
public int hashCode() {
return Objects.hash(value, currency.getCurrencyCode());
}
/**
* 提供一個友好的字符串表示形式,包括金額和貨幣代碼。
*
* @return 字符串表示形式,如 "123.45 USD"
*/
@Override
public String toString() {
return value + " " + currency.getCurrencyCode();
}
}
為什么金額和貨幣可以是值對象?
金額和貨幣作為值對象(Value Object)的原因在于它們符合值對象的核心特征和設(shè)計(jì)原則,具體體現(xiàn)在以下幾個方面:
- 不可變性:金額和貨幣組合表示的是一個具體的、不變的值,比如“100美元”或“50歐元”。一旦創(chuàng)建,這個組合不應(yīng)該被改變,這符合值對象通常設(shè)計(jì)為不可變對象的原則。
- 相等性基于值:兩個金額和貨幣的組合如果數(shù)值和貨幣種類完全相同,就被視為相等,這與值對象的相等性定義一致,即通過其內(nèi)在狀態(tài)而非身份(內(nèi)存地址)來判斷是否相等。
- 無唯一標(biāo)識:與實(shí)體對象(Entity)不同,值對象沒有唯一的、持久的身份標(biāo)識。無論在系統(tǒng)中出現(xiàn)多少次“100美元”,它們都是等價的,不需要區(qū)分是哪個具體的實(shí)例。
- 可共享:由于值對象表示的是不變的值,因此多個對象可以安全地共享同一個值對象實(shí)例,這有助于節(jié)省內(nèi)存并簡化邏輯,尤其是在表達(dá)如商品價格、賬戶余額等場景時。
- 封裝復(fù)雜性:將金額和貨幣封裝在一個值對象中,可以隱藏貨幣轉(zhuǎn)換、格式化等復(fù)雜邏輯,對外提供簡潔的接口,提高了代碼的可讀性和可維護(hù)性。
- 領(lǐng)域驅(qū)動設(shè)計(jì)(DDD)中的概念匹配:在領(lǐng)域驅(qū)動設(shè)計(jì)中,值對象用來描述沒有唯一標(biāo)識符但具有某種描述性的對象。金額和貨幣的組合正是對現(xiàn)實(shí)世界中經(jīng)濟(jì)交易的一種描述,適合用值對象來建模。
綜上所述,將金額和貨幣設(shè)計(jì)為值對象,能夠有效地提升代碼的清晰度、一致性和可維護(hù)性,同時確保了在處理財(cái)務(wù)數(shù)據(jù)時的準(zhǔn)確性和安全性。
創(chuàng)建一個表示價格的值對象(PriceVO)是一個很好的方式來封裝和管理商品價格相關(guān)的數(shù)據(jù),確保數(shù)據(jù)的一致性和精確計(jì)算。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 這個PriceVO類不僅封裝了價格的金額和貨幣類型,還提供了一個計(jì)算含稅價格的方法getTaxInclusiveAmount(),并允許在構(gòu)造時指定稅率。
* 這樣的設(shè)計(jì)使得價格的處理變得靈活且易于理解,同時也保證了在進(jìn)行價格計(jì)算時的準(zhǔn)確性和一致性。
*/
public class PriceVO {
private final BigDecimal amount; // 價格金額,使用BigDecimal確保精度
private final Currency currency; // 貨幣類型
private final BigDecimal taxRate; // 稅率,默認(rèn)為0,表示不含稅
/**
* 構(gòu)造一個新的價格值對象。
*
* @param amount 價格金額,必須大于0
* @param currency 貨幣類型
* @param taxRate 稅率,例如0.08表示8%的稅率,默認(rèn)為0
*/
public PriceVO(BigDecimal amount, Currency currency, BigDecimal taxRate) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Price amount must be greater than zero.");
}
this.amount = amount;
this.currency = currency;
this.taxRate = taxRate != null ? taxRate : BigDecimal.ZERO;
}
/**
* 獲取價格金額。
*
* @return 價格金額
*/
public BigDecimal getAmount() {
return amount;
}
/**
* 獲取貨幣類型。
*
* @return 貨幣類型
*/
public Currency getCurrency() {
return currency;
}
/**
* 獲取含稅價格。
*
* @return 含稅價格
*/
public BigDecimal getTaxInclusiveAmount() {
if (taxRate.compareTo(BigDecimal.ZERO) > 0) {
return amount.multiply(BigDecimal.ONE.add(taxRate));
}
return amount;
}
/**
* 獲取稅率。
*
* @return 稅率
*/
public BigDecimal getTaxRate() {
return taxRate;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PriceVO priceVO = (PriceVO) o;
return amount.equals(priceVO.amount) &&
currency.equals(priceVO.currency) &&
taxRate.equals(priceVO.taxRate);
}
@Override
public int hashCode() {
return Objects.hash(amount, currency, taxRate);
}
@Override
public String toString() {
return amount + " " + currency.getCurrencyCode() +
(taxRate.compareTo(BigDecimal.ZERO) > 0 ? " (Tax: " + taxRate.multiply(new BigDecimal(100)) + "%)" : "");
}
}
創(chuàng)建一個表示工資的值對象(SalaryVO)可以用來封裝員工薪資的細(xì)節(jié),包括基本工資、獎金、扣款等部分,并支持不同貨幣類型。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 這個SalaryVO類封裝了工資計(jì)算的各個方面,包括基本工資、獎金和扣款,并提供了計(jì)算總工資的方法getTotalSalary()。
* 通過使用BigDecimal類型來存儲金額,確保了計(jì)算的精確度。此外,它還支持不同貨幣類型,增加了適用范圍。
* 這樣的設(shè)計(jì)使得工資數(shù)據(jù)的處理更加清晰和高效,易于維護(hù)和擴(kuò)展。
*/
public class SalaryVO {
private final BigDecimal baseSalary; // 基本工資
private final BigDecimal bonus; // 獎金,默認(rèn)為0
private final BigDecimal deductions; // 扣款,默認(rèn)為0
private final Currency currency; // 貨幣類型
/**
* 構(gòu)造一個新的工資值對象。
*
* @param baseSalary 基本工資,必須大于0
* @param bonus 獎金,默認(rèn)為0
* @param deductions 扣款,默認(rèn)為0
* @param currency 貨幣類型
*/
public SalaryVO(BigDecimal baseSalary, BigDecimal bonus, BigDecimal deductions, Currency currency) {
if (baseSalary.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Base salary must be greater than zero.");
}
this.baseSalary = baseSalary;
this.bonus = bonus != null ? bonus : BigDecimal.ZERO;
this.deductions = deductions != null ? deductions : BigDecimal.ZERO;
this.currency = currency;
}
/**
* 獲取基本工資。
*
* @return 基本工資
*/
public BigDecimal getBaseSalary() {
return baseSalary;
}
/**
* 獲取獎金。
*
* @return 獎金
*/
public BigDecimal getBonus() {
return bonus;
}
/**
* 獲取扣款。
*
* @return 扣款
*/
public BigDecimal getDeductions() {
return deductions;
}
/**
* 獲取總工資,即基本工資加上獎金減去扣款。
*
* @return 總工資
*/
public BigDecimal getTotalSalary() {
return baseSalary.add(bonus).subtract(deductions);
}
/**
* 獲取貨幣類型。
*
* @return 貨幣類型
*/
public Currency getCurrency() {
return currency;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SalaryVO salaryVO = (SalaryVO) o;
return baseSalary.equals(salaryVO.baseSalary) &&
bonus.equals(salaryVO.bonus) &&
deductions.equals(salaryVO.deductions) &&
currency.equals(salaryVO.currency);
}
@Override
public int hashCode() {
return Objects.hash(baseSalary, bonus, deductions, currency);
}
@Override
public String toString() {
return "Salary{" +
"baseSalary=" + baseSalary +
", bonus=" + bonus +
", deductions=" + deductions +
", totalSalary=" + getTotalSalary() +
", currency=" + currency.getCurrencyCode() +
'}';
}
}
創(chuàng)建一個費(fèi)用值對象(ExpenseVO)可以幫助我們統(tǒng)一管理和計(jì)算各種費(fèi)用項(xiàng),確保數(shù)據(jù)的準(zhǔn)確性和一致性。
import java.time.LocalDate;
import java.math.BigDecimal;
import java.util.Currency;
/**
* 這個ExpenseVO類封裝了費(fèi)用的基本信息,如費(fèi)用名稱、金額、貨幣類型和發(fā)生日期,提供了獲取這些屬性的方法。
* 通過使用BigDecimal類型來處理金額,確保了金額計(jì)算的精確性。
* 此外,它還允許在創(chuàng)建時指定費(fèi)用發(fā)生的特定日期,或者默認(rèn)為創(chuàng)建時的當(dāng)前日期。
* 這樣的設(shè)計(jì)使得費(fèi)用數(shù)據(jù)的管理更加規(guī)范和靈活。
*/
public class ExpenseVO {
private final String title; // 費(fèi)用標(biāo)題或名稱
private final BigDecimal amount; // 費(fèi)用金額,使用BigDecimal確保精度
private final Currency currency; // 費(fèi)用貨幣類型
private final LocalDate date; // 費(fèi)用發(fā)生日期,默認(rèn)為當(dāng)前日期
/**
* 構(gòu)造一個新的費(fèi)用值對象。
*
* @param title 費(fèi)用標(biāo)題或名稱,不能為空
* @param amount 費(fèi)用金額,必須大于0
* @param currency 費(fèi)用貨幣類型,不能為空
* @param date 費(fèi)用發(fā)生日期,默認(rèn)為當(dāng)前日期
*/
public ExpenseVO(String title, BigDecimal amount, Currency currency, LocalDate date) {
if (title == null || title.isEmpty()) {
throw new IllegalArgumentException("Expense title cannot be null or empty.");
}
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Expense amount must be greater than zero.");
}
if (currency == null) {
throw new IllegalArgumentException("Currency cannot be null.");
}
this.title = title;
this.amount = amount;
this.currency = currency;
this.date = date != null ? date : LocalDate.now();
}
/**
* 獲取費(fèi)用標(biāo)題或名稱。
*
* @return 費(fèi)用標(biāo)題
*/
public String getTitle() {
return title;
}
/**
* 獲取費(fèi)用金額。
*
* @return 費(fèi)用金額
*/
public BigDecimal getAmount() {
return amount;
}
/**
* 獲取貨幣類型。
*
* @return 貨幣類型
*/
public Currency getCurrency() {
return currency;
}
/**
* 獲取費(fèi)用發(fā)生日期。
*
* @return 費(fèi)用日期
*/
public LocalDate getDate() {
return date;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExpenseVO expenseVO = (ExpenseVO) o;
return title.equals(expenseVO.title) &&
amount.equals(expenseVO.amount) &&
currency.equals(expenseVO.currency) &&
date.equals(expenseVO.date);
}
@Override
public int hashCode() {
return Objects.hash(title, amount, currency, date);
}
@Override
public String toString() {
return "Expense{" +
"title='" + title + '\'' +
", amount=" + amount +
", currency=" + currency.getCurrencyCode() +
", date=" + date +
'}';
}
}
度量數(shù)據(jù)
創(chuàng)建一個重量值對象(WeightVO)可以用來封裝和處理重量相關(guān)的數(shù)據(jù),確保在系統(tǒng)中重量的表示和計(jì)算具有一致性和準(zhǔn)確性
/**
* 這個WeightVO類使用BigDecimal來存儲重量值,確保了數(shù)值的精確度,適用于需要高精度計(jì)算的場景。
* 同時,它定義了重量單位,使得重量的表示更加完整和明確。
* 盡管在這個基本實(shí)現(xiàn)中沒有包含單位轉(zhuǎn)換邏輯,但在實(shí)際應(yīng)用中可以根據(jù)需要擴(kuò)展此類,
* 增加單位之間的轉(zhuǎn)換方法,以適應(yīng)不同場景下的重量計(jì)量需求。
*/
public class WeightVO {
private final BigDecimal value; // 重量值,使用BigDecimal確保精度
private final String unit; // 重量單位,如 "kg"(千克)、"g"(克)、"lb"(磅)
/**
* 構(gòu)造一個新的重量值對象。
*
* @param value 重量值,必須大于等于0
* @param unit 重量單位,不能為空,建議使用標(biāo)準(zhǔn)單位
*/
public WeightVO(BigDecimal value, String unit) {
if (value.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Weight value must be non-negative.");
}
if (unit == null || unit.trim().isEmpty()) {
throw new IllegalArgumentException("Weight unit cannot be null or empty.");
}
this.value = value;
this.unit = unit.trim().toLowerCase(); // 統(tǒng)一單位為小寫,便于比較
}
/**
* 獲取重量值。
*
* @return 重量值
*/
public BigDecimal getValue() {
return value;
}
/**
* 獲取重量單位。
*
* @return 重量單位
*/
public String getUnit() {
return unit;
}
/**
* 檢查兩個WeightVO實(shí)例是否表示相同的重量(忽略單位差異)。
*
* @param obj 另一個WeightVO實(shí)例
* @return 如果重量值相同則返回true,否則返回false
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
WeightVO weightVO = (WeightVO) obj;
return value.compareTo(weightVO.value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
/**
* 提供一個友好的字符串表示形式,包括重量值和單位。
*
* @return 字符串表示形式,如 "2.5 kg"
*/
@Override
public String toString() {
return value + " " + unit;
}
}
創(chuàng)建一個長度值對象(LengthVO)旨在封裝長度數(shù)據(jù)及其單位,確保在處理尺寸和距離時的精確性和一致性。
import java.math.BigDecimal;
/**
* 這個LengthVO類通過使用BigDecimal來存儲長度值,
* 確保了數(shù)值的高精度處理,適合于需要精確測量和計(jì)算的場景。
* 同時,它定義了長度單位,使得長度的表述更為明確和規(guī)范。
* 雖然這個基本版本未包含單位轉(zhuǎn)換功能,但可以根據(jù)實(shí)際需求擴(kuò)展此類,
* 添加不同單位間的轉(zhuǎn)換方法,以適應(yīng)多樣的長度計(jì)量需求。
*/
public class LengthVO {
private final BigDecimal value; // 長度值,使用BigDecimal確保精度
private final String unit; // 長度單位,如 "m"(米)、"cm"(厘米)、"in"(英寸)
/**
* 構(gòu)造一個新的長度值對象。
*
* @param value 長度值,必須大于等于0
* @param unit 長度單位,不能為空,建議使用標(biāo)準(zhǔn)單位
*/
public LengthVO(BigDecimal value, String unit) {
if (value.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Length value must be non-negative.");
}
if (unit == null || unit.trim().isEmpty()) {
throw new IllegalArgumentException("Length unit cannot be null or empty.");
}
this.value = value;
this.unit = unit.trim().toLowerCase(); // 統(tǒng)一單位為小寫,便于比較
}
/**
* 獲取長度值。
*
* @return 長度值
*/
public BigDecimal getValue() {
return value;
}
/**
* 獲取長度單位。
*
* @return 長度單位
*/
public String getUnit() {
return unit;
}
/**
* 檢查兩個LengthVO實(shí)例是否表示相同的長度(忽略單位差異)。
*
* @param obj 另一個LengthVO實(shí)例
* @return 如果長度值相同則返回true,否則返回false
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
LengthVO lengthVO = (LengthVO) obj;
return value.compareTo(lengthVO.value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
/**
* 提供一個友好的字符串表示形式,包括長度值和單位。
*
* @return 字符串表示形式,如 "1.5 m"
*/
@Override
public String toString() {
return value + " " + unit;
}
}
創(chuàng)建一個體積值對象(VolumeVO)用于封裝和處理體積相關(guān)的數(shù)據(jù),確保在系統(tǒng)中體積的表示和計(jì)算既精確又一致
import java.math.BigDecimal;
/**
* 這個VolumeVO類利用BigDecimal來存儲體積值,確保了在處理體積數(shù)據(jù)時的高精度。
* 它還定義了體積單位,使得體積的表示更加標(biāo)準(zhǔn)化和清晰。
* 盡管此基本版本沒有包含單位轉(zhuǎn)換邏輯,但根據(jù)實(shí)際應(yīng)用場景,
* 你可以進(jìn)一步擴(kuò)展此類,加入不同體積單位之間的轉(zhuǎn)換方法,
* 以提高其在多場景下的適用性和便利性。
*/
public class VolumeVO {
private final BigDecimal value; // 體積值,使用BigDecimal確保精度
private final String unit; // 體積單位,如 "m3"(立方米)、"L"(升)、"gal"(加侖)
/**
* 構(gòu)造一個新的體積值對象。
*
* @param value 體積值,必須大于等于0
* @param unit 體積單位,不能為空,建議使用標(biāo)準(zhǔn)單位
*/
public VolumeVO(BigDecimal value, String unit) {
if (value.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Volume value must be non-negative.");
}
if (unit == null || unit.trim().isEmpty()) {
throw new IllegalArgumentException("Volume unit cannot be null or empty.");
}
this.value = value;
this.unit = unit.trim().toLowerCase(); // 統(tǒng)一單位為小寫,便于比較
}
/**
* 獲取體積值。
*
* @return 體積值
*/
public BigDecimal getValue() {
return value;
}
/**
* 獲取體積單位。
*
* @return 體積單位
*/
public String getUnit() {
return unit;
}
/**
* 檢查兩個VolumeVO實(shí)例是否表示相同的體積(忽略單位差異)。
*
* @param obj 另一個VolumeVO實(shí)例
* @return 如果體積值相同則返回true,否則返回false
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
VolumeVO volumeVO = (VolumeVO) obj;
return value.compareTo(volumeVO.value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
/**
* 提供一個友好的字符串表示形式,包括體積值和單位。
*
* @return 字符串表示形式,如 "2.5 m3"
*/
@Override
public String toString() {
return value + " " + unit;
}
}
范圍或區(qū)間
創(chuàng)建一個日期范圍值對象(DateRangeVO)可以用來表示起始日期和結(jié)束日期之間的一個時間區(qū)間,這對于處理時間段查詢、事件安排等場景非常有用。
import java.time.LocalDate;
/**
* 這個DateRangeVO類使用LocalDate來表示起始和結(jié)束日期,確保了日期操作的便捷性和準(zhǔn)確性。
* 它提供了判斷日期是否在范圍內(nèi)、計(jì)算持續(xù)天數(shù)等實(shí)用方法,以及重寫了equals和hashCode方法以支持正確的比較和哈希運(yùn)算。
* 這樣的設(shè)計(jì)使得處理日期范圍相關(guān)的業(yè)務(wù)邏輯變得更加簡單和高效。
*/
public class DateRangeVO {
private final LocalDate startDate; // 起始日期,包含該日
private final LocalDate endDate; // 結(jié)束日期,包含該日
/**
* 構(gòu)造一個新的日期范圍值對象。
*
* @param startDate 起始日期,必須不晚于結(jié)束日期
* @param endDate 結(jié)束日期,必須不早于起始日期
*/
public DateRangeVO(LocalDate startDate, LocalDate endDate) {
if (startDate.isAfter(endDate)) {
throw new IllegalArgumentException("Start date must be on or before end date.");
}
this.startDate = startDate;
this.endDate = endDate;
}
/**
* 獲取起始日期。
*
* @return 起始日期
*/
public LocalDate getStartDate() {
return startDate;
}
/**
* 獲取結(jié)束日期。
*
* @return 結(jié)束日期
*/
public LocalDate getEndDate() {
return endDate;
}
/**
* 判斷給定的日期是否位于當(dāng)前日期范圍內(nèi)。
*
* @param date 要檢查的日期
* @return 如果date在范圍內(nèi)則返回true,否則返回false
*/
public boolean contains(LocalDate date) {
return !date.isBefore(startDate) && !date.isAfter(endDate);
}
/**
* 計(jì)算日期范圍的持續(xù)天數(shù)。
*
* @return 日期范圍內(nèi)的天數(shù)
*/
public long durationDays() {
return ChronoUnit.DAYS.between(startDate, endDate) + 1; // 加1是因?yàn)閮啥巳掌诙及趦?nèi)
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
DateRangeVO that = (DateRangeVO) obj;
return startDate.equals(that.startDate) && endDate.equals(that.endDate);
}
@Override
public int hashCode() {
return Objects.hash(startDate, endDate);
}
/**
* 提供一個友好的字符串表示形式,包括起始和結(jié)束日期。
*
* @return 字符串表示形式,如 "2023-04-01 to 2023-04-7"
*/
@Override
public String toString() {
return startDate + " to " + endDate;
}
}
創(chuàng)建一個溫度區(qū)間值對象(TemperatureRangeVO)可以用來表示一個最低溫度到最高溫度之間的區(qū)間,這對于氣象預(yù)報、工業(yè)控制等領(lǐng)域非常有用。
import java.math.BigDecimal;
/**
* 這個TemperatureRangeVO類使用BigDecimal來存儲溫度值,確保了溫度讀數(shù)的高精度。
* 它定義了溫度單位,并提供了判斷某個溫度是否在給定區(qū)間內(nèi)的方法,以及覆蓋了equals和hashCode方法以支持對象的正確比較和集合操作。
* 這樣的設(shè)計(jì)使得處理溫度區(qū)間的數(shù)據(jù)更加方便和準(zhǔn)確。
*/
public class TemperatureRangeVO {
private final BigDecimal minValue; // 最低溫度值,使用BigDecimal確保精度
private final BigDecimal maxValue; // 最高溫度值,使用BigDecimal確保精度
private final String unit; // 溫度單位,如 "C"(攝氏度)或 "F"(華氏度)
/**
* 構(gòu)造一個新的溫度區(qū)間值對象。
*
* @param minValue 最低溫度值,必須小于或等于最大溫度值
* @param maxValue 最高溫度值,必須大于或等于最低溫度值
* @param unit 溫度單位,不能為空,建議使用標(biāo)準(zhǔn)單位
*/
public TemperatureRangeVO(BigDecimal minValue, BigDecimal maxValue, String unit) {
if (minValue.compareTo(maxValue) > 0) {
throw new IllegalArgumentException("Minimum temperature must be less than or equal to maximum temperature.");
}
if (unit == null || unit.trim().isEmpty()) {
throw new IllegalArgumentException("Temperature unit cannot be null or empty.");
}
this.minValue = minValue;
this.maxValue = maxValue;
this.unit = unit.trim().toUpperCase(); // 統(tǒng)一單位為大寫,便于比較
}
/**
* 獲取最低溫度值。
*
* @return 最低溫度值
*/
public BigDecimal getMinValue() {
return minValue;
}
/**
* 獲取最高溫度值。
*
* @return 最高溫度值
*/
public BigDecimal getMaxValue() {
return maxValue;
}
/**
* 獲取溫度單位。
*
* @return 溫度單位
*/
public String getUnit() {
return unit;
}
/**
* 檢查給定的溫度值是否位于當(dāng)前溫度區(qū)間內(nèi)。
*
* @param temp 溫度值
* @return 如果溫度值在區(qū)間內(nèi)則返回true,否則返回false
*/
public boolean contains(BigDecimal temp) {
return temp.compareTo(minValue) >= 0 && temp.compareTo(maxValue) <= 0;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
TemperatureRangeVO that = (TemperatureRangeVO) obj;
return minValue.compareTo(that.minValue) == 0 && maxValue.compareTo(that.maxValue) == 0 && unit.equals(that.unit);
}
@Override
public int hashCode() {
return Objects.hash(minValue, maxValue, unit);
}
/**
* 提供一個友好的字符串表示形式,包括溫度區(qū)間和單位。
*
* @return 字符串表示形式,如 "10°C to 25°C"
*/
@Override
public String toString() {
return minValue + "°" + unit + " to " + maxValue + "°" + unit;
}
}
數(shù)學(xué)模型
創(chuàng)建一個坐標(biāo)值對象(CoordinateVO)可以用來封裝二維空間中的位置信息,通常包括經(jīng)度(longitude)和緯度(latitude)。
/**
* 這個CoordinateVO類使用double類型來存儲經(jīng)度和緯度值,確保了廣泛的兼容性和計(jì)算簡便性。
* 它驗(yàn)證了坐標(biāo)值的有效范圍,并提供了獲取經(jīng)度和緯度的方法。
* 通過重寫equals和hashCode方法,確保了坐標(biāo)值對象可以在集合中正確地進(jìn)行比較和存儲。
* 此外,toString方法提供了易于理解的坐標(biāo)表示形式。
* 這樣的設(shè)計(jì)適用于地理信息系統(tǒng)、地圖應(yīng)用等多種需要處理地理位置信息的場景。
*/
public class CoordinateVO {
private final double longitude; // 經(jīng)度
private final double latitude; // 緯度
/**
* 構(gòu)造一個新的坐標(biāo)值對象。
*
* @param longitude 經(jīng)度,取值范圍通常是 -180 到 180
* @param latitude 緯度,取值范圍通常是 -90 到 90
*/
public CoordinateVO(double longitude, double latitude) {
if (longitude < -180 || longitude > 180) {
throw new IllegalArgumentException("Longitude must be between -180 and 180.");
}
if (latitude < -90 || latitude > 90) {
throw new IllegalArgumentException("Latitude must be between -90 and 90.");
}
this.longitude = longitude;
this.latitude = latitude;
}
/**
* 獲取經(jīng)度。
*
* @return 經(jīng)度值
*/
public double getLongitude() {
return longitude;
}
/**
* 獲取緯度。
*
* @return 緯度值
*/
public double getLatitude() {
return latitude;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
CoordinateVO coordinateVO = (CoordinateVO) obj;
return Double.compare(coordinateVO.longitude, longitude) == 0 && Double.compare(coordinateVO.latitude, latitude) == 0;
}
@Override
public int hashCode() {
return Objects.hash(longitude, latitude);
}
/**
* 提供一個友好的字符串表示形式,展示經(jīng)緯度坐標(biāo)。
*
* @return 字符串表示形式,如 "(100.75, 30.25)"
*/
@Override
public String toString() {
return "(" + longitude + ", " + latitude + ")";
}
}
創(chuàng)建一個向量值對象(VectorVO)可以用來表示具有大小(magnitude)和方向的量,通常在物理、工程和計(jì)算機(jī)圖形學(xué)等領(lǐng)域中使用。這里我們以二維向量為例,它包含x分量和y分量。
/**
* 這個VectorVO類使用double類型來存儲向量的x分量和y分量,
* 提供了獲取分量值、計(jì)算向量大小(模)、向量加法和減法等基本向量操作方法。
* 同時,重寫了equals和hashCode方法以支持向量對象的比較和在集合中的唯一性識別。
* toString方法則用于生成易于閱讀的向量表示。
* 此實(shí)現(xiàn)可以作為基礎(chǔ),根據(jù)具體需求進(jìn)一步擴(kuò)展,比如添加向量的標(biāo)量乘法、點(diǎn)積、叉積等高級操作。
*/
public class VectorVO {
private final double xComponent; // x分量
private final double yComponent; // y分量
/**
* 構(gòu)造一個新的二維向量值對象。
*
* @param xComponent x分量
* @param yComponent y分量
*/
public VectorVO(double xComponent, double yComponent) {
this.xComponent = xComponent;
this.yComponent = yComponent;
}
/**
* 獲取x分量。
*
* @return x分量值
*/
public double getXComponent() {
return xComponent;
}
/**
* 獲取y分量。
*
* @return y分量值
*/
public double getYComponent() {
return yComponent;
}
/**
* 計(jì)算向量的大小(模)。
*
* @return 向量的大小
*/
public double magnitude() {
return Math.sqrt(xComponent * xComponent + yComponent * yComponent);
}
/**
* 向量加法。
*
* @param other 另一個向量
* @return 兩個向量相加的結(jié)果
*/
public VectorVO add(VectorVO other) {
return new VectorVO(this.xComponent + other.xComponent, this.yComponent + other.yComponent);
}
/**
* 向量減法。
*
* @param other 另一個向量
* @return 兩個向量相減的結(jié)果
*/
public VectorVO subtract(VectorVO other) {
return new VectorVO(this.xComponent - other.xComponent, this.yComponent - other.yComponent);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
VectorVO vectorVO = (VectorVO) obj;
return Double.compare(vectorVO.xComponent, xComponent) == 0 && Double.compare(vectorVO.yComponent, yComponent) == 0;
}
@Override
public int hashCode() {
return Objects.hash(xComponent, yComponent);
}
/**
* 提供一個友好的字符串表示形式,展示向量的x和y分量。
*
* @return 字符串表示形式,如 "<1.5, 3.2>"
*/
@Override
public String toString() {
return "<" + xComponent + ", " + yComponent + ">";
}
}
創(chuàng)建線性回歸模型(LinearRegressionModelVO)值對象
線性回歸是一種統(tǒng)計(jì)方法,用于預(yù)測一個連續(xù)響應(yīng)變量與一個或多個預(yù)測變量之間的關(guān)系。這個值對象將包括模型參數(shù)(斜率和截距)、相關(guān)系數(shù)(如R2)、訓(xùn)練數(shù)據(jù)集的摘要統(tǒng)計(jì)信息等。
import java.util.List;
/**
* 這個LinearRegressionModelVO類封裝了線性回歸模型的核心參數(shù),
* 包括斜率、截距、R2值,以及訓(xùn)練數(shù)據(jù)集的特征平均值和標(biāo)準(zhǔn)差列表,
* 這有助于理解和評估模型的質(zhì)量。
* 通過提供這些信息,該值對象能夠支持模型的持久化、比較和調(diào)試等高級操作。
*/
public class LinearRegressionModelVO {
private final double slope; // 斜率,即模型的系數(shù)
private final double intercept; // 截距,即模型的常數(shù)項(xiàng)
private final double rSquared; // R2值,模型擬合優(yōu)度的度量
private final List<Double> featureMeans; // 特征(預(yù)測變量)的平均值列表
private final List<Double> featureStdDevs; // 特征的標(biāo)準(zhǔn)差列表
/**
* 構(gòu)造一個新的線性回歸模型值對象。
*
* @param slope 模型的斜率
* @param intercept 模型的截距
* @param rSquared 模型的R2值
* @param featureMeans 特征的平均值列表
* @param featureStdDevs 特征的標(biāo)準(zhǔn)差列表
*/
public LinearRegressionModelVO(double slope, double intercept, double rSquared,
List<Double> featureMeans, List<Double> featureStdDevs) {
if (featureMeans == null || featureStdDevs == null || featureMeans.size() != featureStdDevs.size()) {
throw new IllegalArgumentException("Feature means and standard deviations lists must not be null and of the same size.");
}
this.slope = slope;
this.intercept = intercept;
this.rSquared = rSquared;
this.featureMeans = featureMeans;
this.featureStdDevs = featureStdDevs;
}
/**
* 獲取模型的斜率。
*
* @return 斜率值
*/
public double getSlope() {
return slope;
}
/**
* 獲取模型的截距。
*
* @return 截距值
*/
public double getIntercept() {
return intercept;
}
/**
* 獲取模型的R2值。
*
* @return R2值
*/
public double getRSquared() {
return rSquared;
}
/**
* 獲取特征的平均值列表。
*
* @return 特征平均值列表
*/
public List<Double> getFeatureMeans() {
return featureMeans;
}
/**
* 獲取特征的標(biāo)準(zhǔn)差列表。
*
* @return 特征標(biāo)準(zhǔn)差列表
*/
public List<Double> getFeatureStdDevs() {
return featureStdDevs;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
LinearRegressionModelVO that = (LinearRegressionModelVO) obj;
return Double.compare(that.slope, slope) == 0 &&
Double.compare(that.intercept, intercept) == 0 &&
Double.compare(that.rSquared, rSquared) == 0 &&
featureMeans.equals(that.featureMeans) &&
featureStdDevs.equals(that.featureStdDevs);
}
@Override
public int hashCode() {
return Objects.hash(slope, intercept, rSquared, featureMeans, featureStdDevs);
}
/**
* 提供一個友好的字符串表示形式,概述模型的關(guān)鍵參數(shù)。
*
* @return 字符串表示形式,如 "Slope: 2.5, Intercept: 1.0, R2: 0.85"
*/
@Override
public String toString() {
return "Slope: " + slope + ", Intercept: " + intercept + ", R2: " + rSquared;
}
}
創(chuàng)建一個多項(xiàng)式回歸模型值對象(PolynomialRegressionModelVO)
多項(xiàng)式回歸是線性回歸的一種擴(kuò)展,允許因變量和一個或多個自變量之間的關(guān)系以多項(xiàng)式形式建模。這個值對象會包含多項(xiàng)式系數(shù)、階次、訓(xùn)練數(shù)據(jù)的性能指標(biāo)等信息。
import java.util.List;
/**
* 這個PolynomialRegressionModelVO類不僅記錄了多項(xiàng)式回歸模型的系數(shù)、階次和R2值,
* 還包含了訓(xùn)練數(shù)據(jù)集的特征統(tǒng)計(jì)信息,有助于深入分析和復(fù)用模型。
* 它支持對復(fù)雜非線性關(guān)系的建模,廣泛應(yīng)用于數(shù)據(jù)分析、科學(xué)計(jì)算和機(jī)器學(xué)習(xí)領(lǐng)域。
*/
public class PolynomialRegressionModelVO {
private final int degree; // 多項(xiàng)式的階次
private final List<Double> coefficients; // 多項(xiàng)式系數(shù)列表,從常數(shù)項(xiàng)到最高次項(xiàng)
private final double rSquared; // R2值,模型擬合優(yōu)度的度量
private final List<Double> featureMeans; // 特征(自變量)的平均值列表
private final List<Double> featureStdDevs; // 特征的標(biāo)準(zhǔn)差列表
/**
* 構(gòu)造一個新的多項(xiàng)式回歸模型值對象。
*
* @param degree 多項(xiàng)式的階次
* @param coefficients 多項(xiàng)式系數(shù)列表
* @param rSquared 模型的R2值
* @param featureMeans 特征的平均值列表
* @param featureStdDevs 特征的標(biāo)準(zhǔn)差列表
*/
public PolynomialRegressionModelVO(int degree, List<Double> coefficients, double rSquared,
List<Double> featureMeans, List<Double> featureStdDevs) {
if (coefficients == null || coefficients.isEmpty() || featureMeans == null || featureStdDevs == null ||
featureMeans.size() != featureStdDevs.size()) {
throw new IllegalArgumentException("Coefficients, feature means, and standard deviations must not be null or incorrectly sized.");
}
if (degree != coefficients.size() - 1) {
throw new IllegalArgumentException("Degree does not match the number of coefficients provided.");
}
this.degree = degree;
this.coefficients = coefficients;
this.rSquared = rSquared;
this.featureMeans = featureMeans;
this.featureStdDevs = featureStdDevs;
}
/**
* 獲取多項(xiàng)式的階次。
*
* @return 階次
*/
public int getDegree() {
return degree;
}
/**
* 獲取多項(xiàng)式系數(shù)列表。
*
* @return 系數(shù)列表
*/
public List<Double> getCoefficients() {
return coefficients;
}
/**
* 獲取模型的R2值。
*
* @return R2值
*/
public double getRSquared() {
return rSquared;
}
/**
* 獲取特征的平均值列表。
*
* @return 特征平均值列表
*/
public List<Double> getFeatureMeans() {
return featureMeans;
}
/**
* 獲取特征的標(biāo)準(zhǔn)差列表。
*
* @return 特征標(biāo)準(zhǔn)差列表
*/
public List<Double> getFeatureStdDevs() {
return featureStdDevs;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PolynomialRegressionModelVO that = (PolynomialRegressionModelVO) obj;
return degree == that.degree &&
coefficients.equals(that.coefficients) &&
Double.compare(that.rSquared, rSquared) == 0 &&
featureMeans.equals(that.featureMeans) &&
featureStdDevs.equals(that.featureStdDevs);
}
@Override
public int hashCode() {
return Objects.hash(degree, coefficients, rSquared, featureMeans, featureStdDevs);
}
/**
* 提供一個友好的字符串表示形式,概述模型的關(guān)鍵參數(shù)。
*
* @return 字符串表示形式,如 "Degree: 3, Coefficients: [2.5, -1.3, 0.6, 1.0], R2: 0.92"
*/
@Override
public String toString() {
return "Degree: " + degree + ", Coefficients: " + coefficients + ", R2: " + rSquared;
}
}
創(chuàng)建一個矩陣值對象(MatrixVO)
用于表示數(shù)學(xué)中的矩陣。矩陣是線性代數(shù)中的基本概念,廣泛應(yīng)用于計(jì)算機(jī)圖形學(xué)、機(jī)器學(xué)習(xí)、工程計(jì)算等多個領(lǐng)域。這個值對象將能夠存儲矩陣的維度信息以及矩陣中的元素值。
import java.util.ArrayList;
import java.util.List;
/**
* 這個MatrixVO類可以用來存儲和操作任意大小的矩陣,包括獲取和設(shè)置特定位置的元素值。
* 通過重寫equals和hashCode方法,確保了不同實(shí)例間的比較邏輯正確。
* toString方法則提供了一個易于閱讀的矩陣表示形式,方便打印和調(diào)試。
* 此類設(shè)計(jì)適用于需要在軟件系統(tǒng)中處理矩陣運(yùn)算的場景,例如計(jì)算密集型應(yīng)用、算法開發(fā)等。
*/
public class MatrixVO {
private final int rows; // 矩陣的行數(shù)
private final int columns; // 矩陣的列數(shù)
private final List<List<Double>> elements; // 矩陣元素,內(nèi)部列表代表每行的元素
/**
* 構(gòu)造一個新的矩陣值對象。
*
* @param rows 矩陣的行數(shù)
* @param columns 矩陣的列數(shù)
* @param elements 矩陣元素列表,每個子列表代表一行
*/
public MatrixVO(int rows, int columns, List<List<Double>> elements) {
if (rows <= 0 || columns <= 0) {
throw new IllegalArgumentException("Number of rows and columns must be positive.");
}
if (elements == null || elements.size() != rows || !elements.stream().allMatch(row -> row != null && row.size() == columns)) {
throw new IllegalArgumentException("Elements list does not match the specified dimensions.");
}
this.rows = rows;
this.columns = columns;
this.elements = new ArrayList<>(elements); // 使用新列表以避免外部修改影響內(nèi)部狀態(tài)
}
/**
* 獲取矩陣的行數(shù)。
*
* @return 行數(shù)
*/
public int getRows() {
return rows;
}
/**
* 獲取矩陣的列數(shù)。
*
* @return 列數(shù)
*/
public int getColumns() {
return columns;
}
/**
* 獲取指定位置的元素值。
*
* @param row 行索引
* @param column 列索引
* @return 元素值
*/
public double getElementAt(int row, int column) {
return elements.get(row).get(column);
}
/**
* 設(shè)置指定位置的元素值。
*
* @param row 行索引
* @param column 列索引
* @param value 新的元素值
*/
public void setElementAt(int row, int column, double value) {
elements.get(row).set(column, value);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MatrixVO matrixVO = (MatrixVO) obj;
return rows == matrixVO.rows && columns == matrixVO.columns && elements.equals(matrixVO.elements);
}
@Override
public int hashCode() {
return Objects.hash(rows, columns, elements);
}
/**
* 提供一個友好的字符串表示形式,展示矩陣的所有元素。
*
* @return 字符串表示形式,如 "[[1.0, 2.0], [3.0, 4.0]]"
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < rows; i++) {
if (i > 0) sb.append(", ");
sb.append("[");
for (int j = 0; j < columns; j++) {
if (j > 0) sb.append(", ");
sb.append(elements.get(i).get(j));
}
sb.append("]");
}
sb.append("]");
return sb.toString();
}
}

浙公網(wǎng)安備 33010602011771號