3.27 Tutorial 4
To examine whether two instance are same
-
check whether it is null.
-
check whether it is an instance of that class
-
convert the class type and check whether they are equal.
-
check each field
To check the invariant
.... 真是作业造火箭 什么鬼......Calendar.zip
Task 2:
Date.java
package DateAndMonthCalendar;
public class Date {
private int day;
private int month;
private int year;
//!!! Noticing
//The minimum valid date constants.
public static final int MIN_DAY = 15;
public static final int MIN_MONTH = 10;
public static final int MIN_YEAR = 1582;
/**
* Sets the Date to the minimum date 15/10/1582.
*/
//!!! Noticing
public Date() {
day = MIN_DAY;
month = MIN_MONTH;
year = MIN_YEAR;
}
/**
* Sets the Date with a specific day, month, and year
* this date should be greater than minimum date
*/
public Date(int newDay, int newMonth, int newYear) {
day = newDay;
month = newMonth;
year = newYear;
//!!! Noticing
if (!repOk()) {
throw new IllegalArgumentException("Invalid date. Date must be greater or equal than 15/10/1582 and valid.");
}
}
/**
* The algorithm of calculating days in the month
*/
public int daysInMonthAlgorithm(int month) {
//!!! Noticing
/*
if(month == 1 || month == 3 || month == 5 || month == 7
|| month == 8 || month == 10 || month == 12) {
return 31;
}
else if(month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
}
else if(isLeapYear(year)) {
return 29;
}
else {
return 28;
}
*/
switch (month) {
case 1: case 3: case 5: case 7:
case 8: case 10: case 12:
return 31;
case 4: case 6: case 9: case 11:
return 30;
case 2:
return isLeapYear(year) ? 29 : 28;
default:
throw new IllegalArgumentException("Invalid month: " + month);
}
}
/**
* return how many days the month of a Date has.
*/
public int daysInMonth() {
return daysInMonthAlgorithm(month);
}
private int daysInMonth(int month) {
return daysInMonthAlgorithm(month);
}
/**
* determine whether the year is leap year
*/
public boolean isLeapYear() {
return isLeapYear(year);
}
private boolean isLeapYear(int year) {
return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));
}
/**
* Methods to get the day, month, and year of a Date.
*/
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
public int getYear() {
return year;
}
/**
* Change the day, month, and year of a Date
*/
public void changeDate(int newDay, int newMonth, int newYear) {
/*day = newDay;
month = newMonth;
year = newYear;
*/
//!!! Noticing
int oldDay = day, oldMonth = month, oldYear = year;
day = newDay;
month = newMonth;
year = newYear;
if (!repOk()) {
// Revert changes if new values are invalid.
day = oldDay;
month = oldMonth;
year = oldYear;
throw new IllegalArgumentException("Invalid date change. Date must be greater or equal than 15/10/1582 and valid.");
}
}
/** if this date is less (-1), equal
* (0), or greater (1) than the other Date
*/
public int compareTo(Date other) {
if(this.getYear() > other.getYear()) {
return 1;
}
else if(this.getYear() < other.getYear()) {
return -1;
}
else {
if(this.getMonth() > other.getMonth()) {
return 1;
}
else if(this.getMonth() < other.getMonth()) {
return -1;
}
else {
if(this.getDay() > other.getDay()) {
return 1;
}
else if(this.getDay() < other.getDay()) {
return -1;
}
else {
return 0;
}
}
}
}
/** The algorithm to calculate the difference days from 1/1/1 to this Date
*/
public int countDays() {
int total = 0;
int i = 1;
while(i < this.getYear()) {
total += isLeapYear(i) ? 366 : 365;
i++;
}
i = 1;
while(i < this.getMonth()) {
total += daysInMonth(i);
i++;
}
total += this.getDay();
return total;
}
/** to calculate the difference in days between another Date
* which must be less or equal than the current one.
*/
//!!! Noticing
public int differenceInDays(Date other) {
//other < this
if (this.compareTo(other) < 0) {
throw new IllegalArgumentException("Other date must be less than or equal to the current date.");
}
return this.countDays() - other.countDays();
}
/**
* Returns true if this Date meets the class invariants:
* - The date is not before 15/10/1582.
* - The month is between 1 and 12.
* - The day is between 1 and the maximum days in that month.
*/
public boolean repOk() {
/*
if(year < 1582) {
return false;
}
else if(month < 10) {
return false;
}
else if(day < 15) {
return false;
}
*/
if (year < MIN_YEAR) {
return false;
}
if (year == MIN_YEAR) {
if (month < MIN_MONTH) {
return false;
}
if (month == MIN_MONTH && day < MIN_DAY) {
return false;
}
}
if (month < 1 || month > 12) {
return false;
}
if (day < 1 || day > daysInMonth(month)) {
return false;
}
return true;
}
/**
* Checks if this Date is equal to another.
* Two dates are equal if they have the same day, month, and year.
*/
@Override
public boolean equals(Object other) {
// Check if it's the same object reference
if (this == other) {
return true;
}
// Check if other is null or not a Date object
if (other == null || !(other instanceof Date)) {
return false;
}
// Cast other to Date
Date otherDate = (Date) other;
// Compare day, month, and year
return this.day == otherDate.day &&
this.month == otherDate.month &&
this.year == otherDate.year;
}
/**
* return a string representation of a Date
*/
@Override
public String toString() {
if(month < 10) {
return day + "/0" + month + "/" + year;
}
else {
return day + "/" + month + "/" + year;
}
}
}
MonthCalendar.java
package DateAndMonthCalendar;
import java.util.ArrayList;
public class MonthCalendar {
private int year;
private int month;
private ArrayList<Date> freeDates;
private ArrayList<Date> busyDates;
/**
* Constructor for MonthCalendar.
* Preconditions:
* - year must be >= 1582.
* - month must be between 1 and 12, and if year is 1582, month must be >= 10.
* Postcondition: All valid Dates in the month are initially marked as free.
*/
public MonthCalendar(int year, int month) {
if (year < Date.MIN_YEAR) {
throw new IllegalArgumentException("Year must be at least " + Date.MIN_YEAR);
}
if (month < 1 || month > 12) {
throw new IllegalArgumentException("Month must be between 1 and 12");
}
if (year == Date.MIN_YEAR && month < Date.MIN_MONTH) {
throw new IllegalArgumentException("For year " + Date.MIN_YEAR + ", month must be at least " + Date.MIN_MONTH);
}
this.year = year;
this.month = month;
freeDates = new ArrayList<Date>();
busyDates = new ArrayList<Date>();
int startDay = 1;
if (year == Date.MIN_YEAR && month == Date.MIN_MONTH) {
startDay = Date.MIN_DAY;
}
int numDays;
if (year == Date.MIN_YEAR && month == Date.MIN_MONTH) {
Date dummy = new Date(Date.MIN_DAY, month, year);
numDays = dummy.daysInMonth();
} else {
Date dummy = new Date(1, month, year);
numDays = dummy.daysInMonth();
}
for (int d = startDay; d <= numDays; d++) {
Date current = new Date(d, month, year);
freeDates.add(current);
}
if (!repOk()) {
throw new IllegalStateException("Invariant violation in MonthCalendar constructor.");
}
}
/**
* Marks a valid, free Date as busy.
* Precondition: The Date is in this month/year and is currently free.
* Postcondition: The Date is moved from freeDates to busyDates.
*/
public void markAsBusy(Date date) {
if (date.getYear() != this.year || date.getMonth() != this.month) {
throw new IllegalArgumentException("Date is not in the calendar month.");
}
if (!freeDates.contains(date)) {
throw new IllegalArgumentException("Date is not free or does not exist.");
}
freeDates.remove(date);
busyDates.add(date);
if (!repOk()) {
throw new IllegalStateException("Invariant violation after marking date as busy.");
}
}
/**
* Marks a valid, busy Date as free.
* Precondition: The Date is in this month/year and is currently busy.
* Postcondition: The Date is moved from busyDates to freeDates.
*/
public void freeDate(Date date) {
if (date.getYear() != this.year || date.getMonth() != this.month) {
throw new IllegalArgumentException("Date is not in the calendar month.");
}
if (!busyDates.contains(date)) {
throw new IllegalArgumentException("Date is not busy.");
}
busyDates.remove(date);
freeDates.add(date);
if (!repOk()) {
throw new IllegalStateException("Invariant violation after freeing date.");
}
}
/**
* Returns a string representation of the MonthCalendar.
* Format:
* Month calendar: ¡month name¿/¡year¿
* Busy dates:
* list of busy dates (one per line)
* Free dates:
* list of free dates (one per line)
*/
public String toString() {
String s = "Month calendar: " + getMonthName(month) + "/" + year + "\n";
s = s + "Busy dates:\n";
if (busyDates.size() == 0) {
s = s + "None\n";
} else {
for (int i = 0; i < busyDates.size(); i++) {
s = s + busyDates.get(i).toString() + "\n";
}
}
s = s + "Free dates:\n";
if (freeDates.size() == 0) {
s = s + "None\n";
} else {
for (int i = 0; i < freeDates.size(); i++) {
s = s + freeDates.get(i).toString() + "\n";
}
}
return s;
}
/**
* Helper method to return the month name.
*/
private String getMonthName(int month) {
String[] months = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
return months[month - 1];
}
/**
* Class invariant check.
* Returns true if the state of this MonthCalendar is valid.
*/
public boolean repOk() {
// Check year and month invariants.
if (year < Date.MIN_YEAR) {
return false;
}
if (year == Date.MIN_YEAR && month < Date.MIN_MONTH) {
return false;
}
if (month < 1 || month > 12) {
return false;
}
// Check that every Date in freeDates and busyDates belongs to this calendar and is valid.
for (int i = 0; i < freeDates.size(); i++) {
Date d = freeDates.get(i);
if (d.getYear() != year || d.getMonth() != month || !d.repOk()) {
return false;
}
}
for (int i = 0; i < busyDates.size(); i++) {
Date d = busyDates.get(i);
if (d.getYear() != year || d.getMonth() != month || !d.repOk()) {
return false;
}
}
// Ensure no Date is both free and busy.
for (int i = 0; i < freeDates.size(); i++) {
Date d = freeDates.get(i);
if (busyDates.contains(d)) {
return false;
}
}
return true;
}
}
MonthOriganizer.java
import DateAndMonthCalendar.MonthCalendar;
import DateAndMonthCalendar.Date;
import java.util.Scanner;
public class MonthOrganizer {
/**
* Main method that allows the user to interact with a MonthCalendar.
* It lets the user mark dates as busy, free busy dates, and display the calendar.
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Welcome to Month Organizer");
System.out.print("Enter year (>=1582): ");
int year = scanner.nextInt();
System.out.print("Enter month (1-12): ");
int month = scanner.nextInt();
MonthCalendar calendar;
try {
calendar = new MonthCalendar(year, month);
} catch (IllegalArgumentException e) {
System.out.println("Error creating calendar: " + e.getMessage());
scanner.close();
return;
}
boolean exit = false;
while (!exit) {
System.out.println("\nSelect an option:");
System.out.println("1. Mark a date as busy");
System.out.println("2. Free a busy date");
System.out.println("3. Display calendar");
System.out.println("4. Exit");
System.out.print("Choice: ");
int choice = scanner.nextInt();
switch (choice) {
case 1:
System.out.print("Enter day to mark as busy: ");
int busyDay = scanner.nextInt();
try {
Date busyDate = new Date(busyDay, month, year);
calendar.markAsBusy(busyDate);
System.out.println("Date marked as busy.");
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
break;
case 2:
System.out.print("Enter day to free: ");
int freeDay = scanner.nextInt();
try {
Date freeDate = new Date(freeDay, month, year);
calendar.freeDate(freeDate);
System.out.println("Date freed.");
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
break;
case 3:
System.out.println(calendar.toString());
break;
case 4:
exit = true;
break;
default:
System.out.println("Invalid option.");
}
}
scanner.close();
System.out.println("Goodbye!");
}
}