示例拓展
金额和货币
创建一个表示金额和货币的值对象(AmountVO),在系统中统一处理货币相关的数据,确保精度和一致性。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 这个AmountVO类使用BigDecimal来精确存储金额值,避免了浮点运算可能带来的精度问题。
同时,利用Currency类来表示货币类型,确保了货币信息的标准化。
此外,重写了equals、hashCode和toString方法以支持比较、哈希运算和提供人性化的字符串表示。
*/
public class AmountVO {
private final BigDecimal value; // 金额值,使用BigDecimal以精确表示货币值
private final Currency currency; // 货币类型,使用Java标准库中的Currency类
/**
* 构造一个新的金额值对象。
*
* @param value 金额值,要求为正数
* @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实例是否代表相同的金额(考虑货币)。
*
* @param obj 另一个AmountVO实例
* @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)的原因在于它们符合值对象的核心特征和设计原则,具体体现在以下几个方面:
- 不可变性:金额和货币组合表示的是一个具体的、不变的值,比如“100美元”或“50欧元”。一旦创建,这个组合不应该被改变,这符合值对象通常设计为不可变对象的原则。
- 相等性基于值:两个金额和货币的组合如果数值和货币种类完全相同,就被视为相等,这与值对象的相等性定义一致,即通过其内在状态而非身份(内存地址)来判断是否相等。
- 无唯一标识:与实体对象(Entity)不同,值对象没有唯一的、持久的身份标识。无论在系统中出现多少次“100美元”,它们都是等价的,不需要区分是哪个具体的实例。
- 可共享:由于值对象表示的是不变的值,因此多个对象可以安全地共享同一个值对象实例,这有助于节省内存并简化逻辑,尤其是在表达如商品价格、账户余额等场景时。
- 封装复杂性:将金额和货币封装在一个值对象中,可以隐藏货币转换、格式化等复杂逻辑,对外提供简洁的接口,提高了代码的可读性和可维护性。
- 领域驱动设计(DDD)中的概念匹配:在领域驱动设计中,值对象用来描述没有唯一标识符但具有某种描述性的对象。金额和货币的组合正是对现实世界中经济交易的一种描述,适合用值对象来建模。
综上所述,将金额和货币设计为值对象,能够有效地提升代码的清晰度、一致性和可维护性,同时确保了在处理财务数据时的准确性和安全性。
创建一个表示价格的值对象(PriceVO)是一个很好的方式来封装和管理商品价格相关的数据,确保数据的一致性和精确计算。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 这个PriceVO类不仅封装了价格的金额和货币类型,还提供了一个计算含税价格的方法getTaxInclusiveAmount(),并允许在构造时指定税率。
* 这样的设计使得价格的处理变得灵活且易于理解,同时也保证了在进行价格计算时的准确性和一致性。
*/
public class PriceVO {
private final BigDecimal amount; // 价格金额,使用BigDecimal确保精度
private final Currency currency; // 货币类型
private final BigDecimal taxRate; // 税率,默认为0,表示不含税
/**
* 构造一个新的价格值对象。
*
* @param amount 价格金额,必须大于0
* @param currency 货币类型
* @param taxRate 税率,例如0.08表示8%的税率,默认为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)) + "%)" : "");
}
}
创建一个表示工资的值对象(SalaryVO)可以用来封装员工薪资的细节,包括基本工资、奖金、扣款等部分,并支持不同货币类型。
import java.math.BigDecimal;
import java.util.Currency;
/**
* 这个SalaryVO类封装了工资计算的各个方面,包括基本工资、奖金和扣款,并提供了计算总工资的方法getTotalSalary()。
* 通过使用BigDecimal类型来存储金额,确保了计算的精确度。此外,它还支持不同货币类型,增加了适用范围。
* 这样的设计使得工资数据的处理更加清晰和高效,易于维护和扩展。
*/
public class SalaryVO {
private final BigDecimal baseSalary; // 基本工资
private final BigDecimal bonus; // 奖金,默认为0
private final BigDecimal deductions; // 扣款,默认为0
private final Currency currency; // 货币类型
/**
* 构造一个新的工资值对象。
*
* @param baseSalary 基本工资,必须大于0
* @param bonus 奖金,默认为0
* @param deductions 扣款,默认为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() +
'}';
}
}
创建一个费用值对象(ExpenseVO)可以帮助我们统一管理和计算各种费用项,确保数据的准确性和一致性。
import java.time.LocalDate;
import java.math.BigDecimal;
import java.util.Currency;
/**
* 这个ExpenseVO类封装了费用的基本信息,如费用名称、金额、货币类型和发生日期,提供了获取这些属性的方法。
* 通过使用BigDecimal类型来处理金额,确保了金额计算的精确性。
* 此外,它还允许在创建时指定费用发生的特定日期,或者默认为创建时的当前日期。
* 这样的设计使得费用数据的管理更加规范和灵活。
*/
public class ExpenseVO {
private final String title; // 费用标题或名称
private final BigDecimal amount; // 费用金额,使用BigDecimal确保精度
private final Currency currency; // 费用货币类型
private final LocalDate date; // 费用发生日期,默认为当前日期
/**
* 构造一个新的费用值对象。
*
* @param title 费用标题或名称,不能为空
* @param amount 费用金额,必须大于0
* @param currency 费用货币类型,不能为空
* @param date 费用发生日期,默认为当前日期
*/
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();
}
/**
* 获取费用标题或名称。
*
* @return 费用标题
*/
public String getTitle() {
return title;
}
/**
* 获取费用金额。
*
* @return 费用金额
*/
public BigDecimal getAmount() {
return amount;
}
/**
* 获取货币类型。
*
* @return 货币类型
*/
public Currency getCurrency() {
return currency;
}
/**
* 获取费用发生日期。
*
* @return 费用日期
*/
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 +
'}';
}
}
度量数据
创建一个重量值对象(WeightVO)可以用来封装和处理重量相关的数据,确保在系统中重量的表示和计算具有一致性和准确性
/**
* 这个WeightVO类使用BigDecimal来存储重量值,确保了数值的精确度,适用于需要高精度计算的场景。
* 同时,它定义了重量单位,使得重量的表示更加完整和明确。
* 尽管在这个基本实现中没有包含单位转换逻辑,但在实际应用中可以根据需要扩展此类,
* 增加单位之间的转换方法,以适应不同场景下的重量计量需求。
*/
public class WeightVO {
private final BigDecimal value; // 重量值,使用BigDecimal确保精度
private final String unit; // 重量单位,如 "kg"(千克)、"g"(克)、"lb"(磅)
/**
* 构造一个新的重量值对象。
*
* @param value 重量值,必须大于等于0
* @param unit 重量单位,不能为空,建议使用标准单位
*/
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(); // 统一单位为小写,便于比较
}
/**
* 获取重量值。
*
* @return 重量值
*/
public BigDecimal getValue() {
return value;
}
/**
* 获取重量单位。
*
* @return 重量单位
*/
public String getUnit() {
return unit;
}
/**
* 检查两个WeightVO实例是否表示相同的重量(忽略单位差异)。
*
* @param obj 另一个WeightVO实例
* @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;
}
}
创建一个长度值对象(LengthVO)旨在封装长度数据及其单位,确保在处理尺寸和距离时的精确性和一致性。
import java.math.BigDecimal;
/**
* 这个LengthVO类通过使用BigDecimal来存储长度值,
* 确保了数值的高精度处理,适合于需要精确测量和计算的场景。
* 同时,它定义了长度单位,使得长度的表述更为明确和规范。
* 虽然这个基本版本未包含单位转换功能,但可以根据实际需求扩展此类,
* 添加不同单位间的转换方法,以适应多样的长度计量需求。
*/
public class LengthVO {
private final BigDecimal value; // 长度值,使用BigDecimal确保精度
private final String unit; // 长度单位,如 "m"(米)、"cm"(厘米)、"in"(英寸)
/**
* 构造一个新的长度值对象。
*
* @param value 长度值,必须大于等于0
* @param unit 长度单位,不能为空,建议使用标准单位
*/
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(); // 统一单位为小写,便于比较
}
/**
* 获取长度值。
*
* @return 长度值
*/
public BigDecimal getValue() {
return value;
}
/**
* 获取长度单位。
*
* @return 长度单位
*/
public String getUnit() {
return unit;
}
/**
* 检查两个LengthVO实例是否表示相同的长度(忽略单位差异)。
*
* @param obj 另一个LengthVO实例
* @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;
}
}
创建一个体积值对象(VolumeVO)用于封装和处理体积相关的数据,确保在系统中体积的表示和计算既精确又一致
import java.math.BigDecimal;
/**
* 这个VolumeVO类利用BigDecimal来存储体积值,确保了在处理体积数据时的高精度。
* 它还定义了体积单位,使得体积的表示更加标准化和清晰。
* 尽管此基本版本没有包含单位转换逻辑,但根据实际应用场景,
* 你可以进一步扩展此类,加入不同体积单位之间的转换方法,
* 以提高其在多场景下的适用性和便利性。
*/
public class VolumeVO {
private final BigDecimal value; // 体积值,使用BigDecimal确保精度
private final String unit; // 体积单位,如 "m³"(立方米)、"L"(升)、"gal"(加仑)
/**
* 构造一个新的体积值对象。
*
* @param value 体积值,必须大于等于0
* @param unit 体积单位,不能为空,建议使用标准单位
*/
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(); // 统一单位为小写,便于比较
}
/**
* 获取体积值。
*
* @return 体积值
*/
public BigDecimal getValue() {
return value;
}
/**
* 获取体积单位。
*
* @return 体积单位
*/
public String getUnit() {
return unit;
}
/**
* 检查两个VolumeVO实例是否表示相同的体积(忽略单位差异)。
*
* @param obj 另一个VolumeVO实例
* @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 m³"
*/
@Override
public String toString() {
return value + " " + unit;
}
}
范围或区间
创建一个日期范围值对象(DateRangeVO)可以用来表示起始日期和结束日期之间的一个时间区间,这对于处理时间段查询、事件安排等场景非常有用。
import java.time.LocalDate;
/**
* 这个DateRangeVO类使用LocalDate来表示起始和结束日期,确保了日期操作的便捷性和准确性。
* 它提供了判断日期是否在范围内、计算持续天数等实用方法,以及重写了equals和hashCode方法以支持正确的比较和哈希运算。
* 这样的设计使得处理日期范围相关的业务逻辑变得更加简单和高效。
*/
public class DateRangeVO {
private final LocalDate startDate; // 起始日期,包含该日
private final LocalDate endDate; // 结束日期,包含该日
/**
* 构造一个新的日期范围值对象。
*
* @param startDate 起始日期,必须不晚于结束日期
* @param endDate 结束日期,必须不早于起始日期
*/
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;
}
/**
* 获取结束日期。
*
* @return 结束日期
*/
public LocalDate getEndDate() {
return endDate;
}
/**
* 判断给定的日期是否位于当前日期范围内。
*
* @param date 要检查的日期
* @return 如果date在范围内则返回true,否则返回false
*/
public boolean contains(LocalDate date) {
return !date.isBefore(startDate) && !date.isAfter(endDate);
}
/**
* 计算日期范围的持续天数。
*
* @return 日期范围内的天数
*/
public long durationDays() {
return ChronoUnit.DAYS.between(startDate, endDate) + 1; // 加1是因为两端日期都包含在内
}
@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);
}
/**
* 提供一个友好的字符串表示形式,包括起始和结束日期。
*
* @return 字符串表示形式,如 "2023-04-01 to 2023-04-7"
*/
@Override
public String toString() {
return startDate + " to " + endDate;
}
}
创建一个温度区间值对象(TemperatureRangeVO)可以用来表示一个最低温度到最高温度之间的区间,这对于气象预报、工业控制等领域非常有用。
import java.math.BigDecimal;
/**
* 这个TemperatureRangeVO类使用BigDecimal来存储温度值,确保了温度读数的高精度。
* 它定义了温度单位,并提供了判断某个温度是否在给定区间内的方法,以及覆盖了equals和hashCode方法以支持对象的正确比较和集合操作。
* 这样的设计使得处理温度区间的数据更加方便和准确。
*/
public class TemperatureRangeVO {
private final BigDecimal minValue; // 最低温度值,使用BigDecimal确保精度
private final BigDecimal maxValue; // 最高温度值,使用BigDecimal确保精度
private final String unit; // 温度单位,如 "C"(摄氏度)或 "F"(华氏度)
/**
* 构造一个新的温度区间值对象。
*
* @param minValue 最低温度值,必须小于或等于最大温度值
* @param maxValue 最高温度值,必须大于或等于最低温度值
* @param unit 温度单位,不能为空,建议使用标准单位
*/
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(); // 统一单位为大写,便于比较
}
/**
* 获取最低温度值。
*
* @return 最低温度值
*/
public BigDecimal getMinValue() {
return minValue;
}
/**
* 获取最高温度值。
*
* @return 最高温度值
*/
public BigDecimal getMaxValue() {
return maxValue;
}
/**
* 获取温度单位。
*
* @return 温度单位
*/
public String getUnit() {
return unit;
}
/**
* 检查给定的温度值是否位于当前温度区间内。
*
* @param temp 温度值
* @return 如果温度值在区间内则返回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);
}
/**
* 提供一个友好的字符串表示形式,包括温度区间和单位。
*
* @return 字符串表示形式,如 "10°C to 25°C"
*/
@Override
public String toString() {
return minValue + "°" + unit + " to " + maxValue + "°" + unit;
}
}
数学模型
创建一个坐标值对象(CoordinateVO)可以用来封装二维空间中的位置信息,通常包括经度(longitude)和纬度(latitude)。
/**
* 这个CoordinateVO类使用double类型来存储经度和纬度值,确保了广泛的兼容性和计算简便性。
* 它验证了坐标值的有效范围,并提供了获取经度和纬度的方法。
* 通过重写equals和hashCode方法,确保了坐标值对象可以在集合中正确地进行比较和存储。
* 此外,toString方法提供了易于理解的坐标表示形式。
* 这样的设计适用于地理信息系统、地图应用等多种需要处理地理位置信息的场景。
*/
public class CoordinateVO {
private final double longitude; // 经度
private final double latitude; // 纬度
/**
* 构造一个新的坐标值对象。
*
* @param longitude 经度,取值范围通常是 -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;
}
/**
* 获取经度。
*
* @return 经度值
*/
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);
}
/**
* 提供一个友好的字符串表示形式,展示经纬度坐标。
*
* @return 字符串表示形式,如 "(100.75, 30.25)"
*/
@Override
public String toString() {
return "(" + longitude + ", " + latitude + ")";
}
}
创建一个向量值对象(VectorVO)可以用来表示具有大小(magnitude)和方向的量,通常在物理、工程和计算机图形学等领域中使用。这里我们以二维向量为例,它包含x分量和y分量。
/**
* 这个VectorVO类使用double类型来存储向量的x分量和y分量,
* 提供了获取分量值、计算向量大小(模)、向量加法和减法等基本向量操作方法。
* 同时,重写了equals和hashCode方法以支持向量对象的比较和在集合中的唯一性识别。
* toString方法则用于生成易于阅读的向量表示。
* 此实现可以作为基础,根据具体需求进一步扩展,比如添加向量的标量乘法、点积、叉积等高级操作。
*/
public class VectorVO {
private final double xComponent; // x分量
private final double yComponent; // y分量
/**
* 构造一个新的二维向量值对象。
*
* @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;
}
/**
* 计算向量的大小(模)。
*
* @return 向量的大小
*/
public double magnitude() {
return Math.sqrt(xComponent * xComponent + yComponent * yComponent);
}
/**
* 向量加法。
*
* @param other 另一个向量
* @return 两个向量相加的结果
*/
public VectorVO add(VectorVO other) {
return new VectorVO(this.xComponent + other.xComponent, this.yComponent + other.yComponent);
}
/**
* 向量减法。
*
* @param other 另一个向量
* @return 两个向量相减的结果
*/
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 + ">";
}
}
创建线性回归模型(LinearRegressionModelVO)值对象
线性回归是一种统计方法,用于预测一个连续响应变量与一个或多个预测变量之间的关系。这个值对象将包括模型参数(斜率和截距)、相关系数(如R²)、训练数据集的摘要统计信息等。
import java.util.List;
/**
* 这个LinearRegressionModelVO类封装了线性回归模型的核心参数,
* 包括斜率、截距、R²值,以及训练数据集的特征平均值和标准差列表,
* 这有助于理解和评估模型的质量。
* 通过提供这些信息,该值对象能够支持模型的持久化、比较和调试等高级操作。
*/
public class LinearRegressionModelVO {
private final double slope; // 斜率,即模型的系数
private final double intercept; // 截距,即模型的常数项
private final double rSquared; // R²值,模型拟合优度的度量
private final List<Double> featureMeans; // 特征(预测变量)的平均值列表
private final List<Double> featureStdDevs; // 特征的标准差列表
/**
* 构造一个新的线性回归模型值对象。
*
* @param slope 模型的斜率
* @param intercept 模型的截距
* @param rSquared 模型的R²值
* @param featureMeans 特征的平均值列表
* @param featureStdDevs 特征的标准差列表
*/
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;
}
/**
* 获取模型的R²值。
*
* @return R²值
*/
public double getRSquared() {
return rSquared;
}
/**
* 获取特征的平均值列表。
*
* @return 特征平均值列表
*/
public List<Double> getFeatureMeans() {
return featureMeans;
}
/**
* 获取特征的标准差列表。
*
* @return 特征标准差列表
*/
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);
}
/**
* 提供一个友好的字符串表示形式,概述模型的关键参数。
*
* @return 字符串表示形式,如 "Slope: 2.5, Intercept: 1.0, R²: 0.85"
*/
@Override
public String toString() {
return "Slope: " + slope + ", Intercept: " + intercept + ", R²: " + rSquared;
}
}
创建一个多项式回归模型值对象(PolynomialRegressionModelVO)
多项式回归是线性回归的一种扩展,允许因变量和一个或多个自变量之间的关系以多项式形式建模。这个值对象会包含多项式系数、阶次、训练数据的性能指标等信息。
import java.util.List;
/**
* 这个PolynomialRegressionModelVO类不仅记录了多项式回归模型的系数、阶次和R²值,
* 还包含了训练数据集的特征统计信息,有助于深入分析和复用模型。
* 它支持对复杂非线性关系的建模,广泛应用于数据分析、科学计算和机器学习领域。
*/
public class PolynomialRegressionModelVO {
private final int degree; // 多项式的阶次
private final List<Double> coefficients; // 多项式系数列表,从常数项到最高次项
private final double rSquared; // R²值,模型拟合优度的度量
private final List<Double> featureMeans; // 特征(自变量)的平均值列表
private final List<Double> featureStdDevs; // 特征的标准差列表
/**
* 构造一个新的多项式回归模型值对象。
*
* @param degree 多项式的阶次
* @param coefficients 多项式系数列表
* @param rSquared 模型的R²值
* @param featureMeans 特征的平均值列表
* @param featureStdDevs 特征的标准差列表
*/
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;
}
/**
* 获取多项式的阶次。
*
* @return 阶次
*/
public int getDegree() {
return degree;
}
/**
* 获取多项式系数列表。
*
* @return 系数列表
*/
public List<Double> getCoefficients() {
return coefficients;
}
/**
* 获取模型的R²值。
*
* @return R²值
*/
public double getRSquared() {
return rSquared;
}
/**
* 获取特征的平均值列表。
*
* @return 特征平均值列表
*/
public List<Double> getFeatureMeans() {
return featureMeans;
}
/**
* 获取特征的标准差列表。
*
* @return 特征标准差列表
*/
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);
}
/**
* 提供一个友好的字符串表示形式,概述模型的关键参数。
*
* @return 字符串表示形式,如 "Degree: 3, Coefficients: [2.5, -1.3, 0.6, 1.0], R²: 0.92"
*/
@Override
public String toString() {
return "Degree: " + degree + ", Coefficients: " + coefficients + ", R²: " + rSquared;
}
}
创建一个矩阵值对象(MatrixVO)
用于表示数学中的矩阵。矩阵是线性代数中的基本概念,广泛应用于计算机图形学、机器学习、工程计算等多个领域。这个值对象将能够存储矩阵的维度信息以及矩阵中的元素值。
import java.util.ArrayList;
import java.util.List;
/**
* 这个MatrixVO类可以用来存储和操作任意大小的矩阵,包括获取和设置特定位置的元素值。
* 通过重写equals和hashCode方法,确保了不同实例间的比较逻辑正确。
* toString方法则提供了一个易于阅读的矩阵表示形式,方便打印和调试。
* 此类设计适用于需要在软件系统中处理矩阵运算的场景,例如计算密集型应用、算法开发等。
*/
public class MatrixVO {
private final int rows; // 矩阵的行数
private final int columns; // 矩阵的列数
private final List<List<Double>> elements; // 矩阵元素,内部列表代表每行的元素
/**
* 构造一个新的矩阵值对象。
*
* @param rows 矩阵的行数
* @param columns 矩阵的列数
* @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); // 使用新列表以避免外部修改影响内部状态
}
/**
* 获取矩阵的行数。
*
* @return 行数
*/
public int getRows() {
return rows;
}
/**
* 获取矩阵的列数。
*
* @return 列数
*/
public int getColumns() {
return columns;
}
/**
* 获取指定位置的元素值。
*
* @param row 行索引
* @param column 列索引
* @return 元素值
*/
public double getElementAt(int row, int column) {
return elements.get(row).get(column);
}
/**
* 设置指定位置的元素值。
*
* @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();
}
}
标签:02,return,BigDecimal,示例,param,value,obj,public,DDD
From: https://www.cnblogs.com/dolphinmind/p/18303938