In Modula-2 and Ada 83, it is easy to separate the interface from the implementation. So having this background, and having taught Modula-2 in this way for many years ([3]), when I started to look at Java I wondered whether the same style of programming could be achieved (and should be adopted) in Java.
If we need to represent some objects in a Java program, at the same time as producing a class declaration that describes the implementation, we could also produce an interface declaration that describes the operations provided by the methods of the class.
An interface declaration for dates could be:
public interface Date { public int getYear(); public int getMonth(); public int getDay(); public void setYear(int pYear); public void setMonth(int pMonth); public void setDay(int pDay); public boolean equals(Object pObject); public int hashCode(); public String toString(); }
And a class declaration for dates could be:
import java.util.StringTokenizer; public class DateImpl implements Date { private int iYear; private int iMonth; private int iDay; public DateImpl() { this(1970, 1, 1); } public DateImpl(final Date pDate) { final DateImpl tDateImpl = (DateImpl)pDate; iYear = tDateImpl.iYear; iMonth = tDateImpl.iMonth; iDay = tDateImpl.iDay; } public DateImpl(final int pYear, final int pMonth, final int pDay) { iYear = pYear; iMonth = pMonth; iDay = pDay; } public DateImpl(final String pDateString) { try { final StringTokenizer tTokens = new StringTokenizer(pDateString, "-"); final String tYearString = tTokens.nextToken(); iYear = Integer.parseInt(tYearString); final String tMonthString = tTokens.nextToken(); iMonth = Integer.parseInt(tMonthString); final String tDayString = tTokens.nextToken(); iDay = Integer.parseInt(tDayString); } catch(final Exception pException) { iYear = 1970; iMonth = 1; iDay = 1; throw new IllegalArgumentException(); } } public int getYear() { return iYear; } public int getMonth() { return iMonth; } public int getDay() { return iDay; } public void setYear(final int pYear) { iYear = pYear; } public void setMonth(final int pMonth) { iMonth = pMonth; } public void setDay(final int pDay) { iDay = pDay; } public boolean equals(final Object pObject) { if ( pObject==null || getClass()!=pObject.getClass() ) { return false; } final DateImpl tDateImpl = (DateImpl)pObject; return iYear==tDateImpl.iYear && iMonth==tDateImpl.iMonth && iDay==tDateImpl.iDay; } public int hashCode() { return 0; } public String toString() { return iYear + "-" + iMonth/10 + iMonth%10 + "-" + iDay/10 + iDay%10; } }
Whenever possible, the code of a client should use the interface (rather than the class). So:
Date tDate;
public boolean iIsLeap(final Date pDate);
Date tDate = new DateImpl(2000, 12, 25);