java - 实例变量的验证依赖于另一个实例变量是不好的做法吗?
问题描述
让一个变量依赖于另一个变量的状态是不是很糟糕?
例如,我有一个Date
具有属性day
、month
和的类year
。月份和年份可以在其各自的设置器中独立验证,但day
取决于month
和/或year
即一个月/闰年期间的最大天数。我的方法是确保我的构造函数需要所有三个字段,并且它将为day
aftermonth
和调用 setter year
。
不鼓励这样的状态依赖吗?我的类不是不可变的,所以我需要某种验证,我想将验证封装在类本身中,而不是在外部进行。
以下是我当前的代码:
class Date {
private int day;
private int month;
private int year;
public String toString() {
return String.format("%02d/%02d/%04d", month, day, year);
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
// Check if month is valid
if (month < 1 || month > 12) {
throw new IllegalArgumentException(
String.format("%02d is not a valid month", month)
);
} else {
this.month = month;
}
}
public int getYear() {
return year;
}
public void setYear(int year) {
// Check if year is valid
if (year < 1900 || year > 2020) {
throw new IllegalArgumentException(
String.format("%04d is not a valid year", year)
);
} else {
this.year = year;
}
}
public int getDay() {
return day;
}
public void setDay(int day) {
// Check if day is valid
if (day < 1 || day > getMaxNumDaysInMonth(this.getMonth(), this.getYear())) {
throw new IllegalAccessException(
String.format("%02d is not a valid day", day)
);
} else {
this.day = day;
}
}
Date(int month, int day, int year) {
setMonth(month);
setYear(year);
setDay(day);
}
private final int[] MAX_MONTH_DAYS = {
0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/**
* Gets the maximum number of days in a month
* Depends on the month and whether the year is a leap year
* @param month
* @param year
* @return
*/
private int getMaxNumDaysInMonth(int month, int year) {
// Check if date is valid
if (year < 1 || month < 1 || month > 12) {
throw new IllegalArgumentException(
String.format("%04d-%02d is not a valid date", year, month)
);
} else {
// Adjust February if year is a leap year
if (month == 2) {
if (isLeapYear(year)) {
return MAX_MONTH_DAYS[month];
} else {
return MAX_MONTH_DAYS[month] - 1;
}
} else {
return MAX_MONTH_DAYS[month];
}
}
} // end getNumDaysInMonth
/**
* Returns true if year is a Leap year
* Returns false otherwise
* @param year
* @return
*/
private boolean isLeapYear(int year) {
return (year % 4) == 0 && (year % 100 !=0 || year % 400 == 0);
}
} // end Date class
解决方案
参数验证总是一个好主意,实际上也有专门为你做这种事情的类,让它变得更容易。
public void setMonth(int month) {
Preconditions.checkArgument(month >= 1 && month <= 12, String.format("%s is not a valid month.", month));
this.month = month.
}
关于可变性的无关说明
如果您希望此类是不可变的,但仍允许使用 setMonth 之类的方法,则您始终可以将字段设置为 final 并返回一个带有新月份的新 Date 。
class Date {
private final int month;
private final int day;
private final int year;
// constructor
public Date setMonth(int month) {
// check argument is valid
return new Date(day, month, year);
}
}
Date date = new Date(2020, 3, 7);
date = date.setMonth(4);
你知道这已经完成了吗?
你需要创建一个管理日期的类吗?这已经存在,并且在过去几年中得到了极大的改进。
LocalDate localDate = LocalDate.now();
localDate = localDate.withMonth(4).withDayOfMonth(8).withYear(2021);
LocalDateTime localDateTime = LocalDateTime.now();
localDateTime = localDateTime.withHour(9).withMinute(45).withSecond(30).withDayOfMonth(8);
ZonedDateTime zonedDateTime = ZonedDateTime.now();
zonedDateTime = zonedDateTime.withZoneSameLocal(ZoneId.of("UTC"));
推荐阅读
- php - 使用 htaccess 文件进行 URL 重定向,对 url 友好重定向的 url 友好
- excel - 填充 ListBox 时宏卡在 For Each 循环中
- jquery - 使用包含相对路径的图像的 CORS 加载外部 AJAX
- java - raf.seek(pos) 的类比
- regex - 仅使用正则表达式从主页重定向并保留 UTM 参数
- excel - 从 Excel 粘贴到 Word 的 VBA 代码在某些 PC 上运行,在其他 PC 上返回错误 4198
- xamarin.forms - Xamarin 表单中的自定义标签渲染器:OnDraw 从未触发
- c# - 如何在“where”中使用实体框架中的数组值
- javascript - 实例化通过 jQuery.getScript 加载的类时遇到 ReferenceError
- clojure - clojure 是否具有合并如果存在的功能?