My question concerns a specific design convention for methods in Java... but really it would apply to C++, C# and others as well. I don't know what this convention is called, but if there is a standardized convention, I would like to know how to find it. In other words, I wish to describe this convention as I have encountered it and be directed to a place where I can learn more.
Consider java.util.Calendar, specificlaly its child, GregorianCalendar. It has an interesting "getter / setter" convention. Let's say that you instantiate this object:
GregorianCalendar cal = new GregorianCalendar();
The fields of cal now describe the instant in time (down to the millisecond) at which the constructor was called.
Now let's say that you want to access the year field or the month field. You would use the following getters.
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
Notice that it's not cal.getYear() or cal.getMonth(). It looks like there is only one getter method for this class and that the return value is determined by the parameter naming the desired field. I would imagine that within the class there is an enum set up to list the fields... and that the getter function itself is composed of some kind of switch statement.
This type of architecture is not described in any of my books... it is however something that I've been using in my current work... but I've been doing it "my" way (basically just making it up as I go along). If there is a standardized way of doing this that other people use... I'd sure love to know it. Specifically, using enums and switch statements to control the execution of methods.
Thanks so much for your time! This is my first question on this site... I have been a long time lurker though. :)
First, note that the two approaches to API design are not mutually exclusive: one could have both a "get by index" and a "get by name", i.e.
int y1 = cal.get(Calendar.YEAR);
int y2 = cal.getYear();
The primary driving force behind getters controlled by an int constant in the Calendar class is uniformity: it lets users of the Calendar class, such as the date formatters, build code that accesses the calendar by index, without further interpretation. For example, if you wanted to implement a formatter that takes a format string and stores a data structure to pull data from a calendar, you would be able to do it with an array of integers: "dd-mm-yyyy" would become int[] {Calendar.DAY, Calendar.MONTH, Calendar.YEAR}, and you would be able to get the data from calendar with a simple for loop.
Note that one of the reasons why Calendar uses integer constants instead of enums is backward compatibility: that Java did not have enum at the time when the Calendar class has been introduced.
Also note that you do not need a switch statement on an enum or int constants to implement Calendar's getters and setters: they can be implemented as direct reads and writes of the calendar component array.
Actually those are not enums. Those are integers instead. Here is the source code of the Calender get method:
public int get(int field)
{
complete();
return internalGet(field);
}
But having a single method accepting a ENUM and returning different values based on that, is good practice.
As far as the design pattern goes, IMHO it is a variation of Factory pattern.
I'm not actually aware of a name for this specific design, although I've seen it used in a few places. It's certainly not one of the standard "Design Patterns" and is really too small to qualify as a design pattern in its own right. It's just a different way of achieving encapsulation over the more traditional way with multiple getters and setters.
If I was to call it something it would probably be something like "flexible getter" or "extensible getter". I.e. "Rather than having multiple setters lets have one flexible getter"
If I was implementing something like this I would probably use the strategy pattern to do it though:
public abstract class Getter<T> {
private T getData(MyCalendar ob);
}
public static final Getter<Integer> MONTH {
Integer getData(MyCalendar ob) {
return ob.month;
}
}
Then your get method just looks like:
<T>public T get(Getter<T> toGet) {
return toGet.getData(this);
}
This uses polymorphism to fetch the data rather than a massive switch statement. It is fully flexible and extensible while still being type safe, etc.
Related
I am writing some app in which I use integer to represent different types of semantics. For example, I use int to represent both month and year, and I want to avoid accidentally using variables with one semantic in the context requiring the other. I want to use annotation to annotate variables representing month with #Month and ones representing year with #Year, and would like compiler to warn me if unexpected assignment or method call. How do I implement that?
BTW: I don't want to introduce additional classes Month and Year because it is not as efficient and kind of verbose in syntax, e.g. I need to call month.get() to use it where an int is expected, and new Month(m) to create.
I tried to search online but don't find enough document. Any ideas?
Suppose I have the following class:
public class MyClass {
/* Note: Timestamp extends date */
public doSomething(java.sql.Timestamp timestamp){
System.out.println("Timestamp");
...
}
public doSomething(java.util.Date date){
System.out.println("Date");
...
}
}
Suppose that I now exercise my code like this:
MyClass myClass = new MyClass();
Date realDate = new Date();
Timestamp timestamp = new Timestamp(0);
Date casted = new Timestamp(0);
myClass.doSomething(realDate); // prints Date
myClass.doSomething(timestamp); // prints Timestamp
myClass.doSomething(casted); // prints Date!!!!! What?!
The problem that I am having is that since casted is not actually a date, when I use it doesn't work.
Aside: Generally, subclasses not working shouldn't be an issue, however the javadoc for Timestamp says:
Due to the differences between the Timestamp class and the java.util.Date class mentioned above, it is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.
I know that I could do something like this:
public doSomething(java.util.Date date){
if(date instanceof type){
System.out.println("Timestamp");
...
}
System.out.println("Date");
...
}
But this just seems nasty.
Is there a way to get method overloading of subclasses to work without using giant switch statements?
Edit: In short, it seems like Timestamp breaks the Liskov substitution principle - as pointed out by #Mick Mnemonic.
Yep. Not your bug. It's a design quirk of java.util.Date, java.sql.Date, and Timestamp. (Don't be too hard on them. java.util.Date is twenty years old now; they were still figuring this stuff out when they were designing the API.) There's no great way around it if you work directly with these types.
One approach is to avoid using these classes except where you have to, at the boundary with APIs that require them, and use a better-designed set of date-time types elsewhere. In your data access layer, special-case Timestamp etc using instanceof where necessary. And convert everything to Joda-Time (for Java 7) or java.time/JSR-310 (for Java 8) types for your internal code. (If you actually need nanosecond precision in Java 7, you'll need to roll your own Timestamp object to go with the Joda-Time types. Not hard; just make sure to use composition instead of implementation inheritance like the java.util folks did! :) ) You will probably be happier.
First, please note that this question is not a duplicate of this Question:
Java Date vs Calendar. My question is much more specific. The referenced question asks "what" (or "which"), but I already know the "what" and am asking the "why".
I am on a team working on enhancements to an existing Java project for a client. This Java project uses java 6, and does not have Joda Time as a dependency. After inquiring, it looks like adding Joda Time or upgrading to Java 8 are not options.
So, when it comes to representing date/time as a field in an object, we have to use either Calendar or Date for property typing. The legacy code of this project is littered with Objects that use Calendar to represent date/time fields -- fields that we would never have cause to manipulate (as in add or subtract units of time, etc). I know that this is bad practice, as Calendar is a more complex object, while Date is simpler and would work just as well. (And granted, I know that both are fundamentally wrappers for a long of epoch millis, are mutable, and are poorly designed, but again these are our only two options.)
In other words, an object like this:
public class Reservation {
private Guest guest;
// Set only once, never used for calculations
private Calendar dateReserved;
...
}
Should be this instead:
public class Reservation {
private Guest guest;
// Set only once, never used for calculations
private Date dateReserved;
...
}
I then noticed that when adding new Objects for new features, my team was following the same convention of using Calendar instead of Date. When I brought this up, the reply was that it's better to use Calendar because it can do more and doesn't have all these deprecated methods like Date does.
I know that this reasoning is oversimplified. I also see that this answer to the broader question of usage expresses the same view, namely that Calendar should not be used for property typing. However, the answer doesn't contain much explanation as to why Calendar should not be preferred.
So I already know the "What". But I'm trying to make the case to my team, so my question is, "Why"? Why, when property typing, should Date be preferred to Calendar? What are the disadvantages of using Calendar instead of Date for property typing?
I agree with Jon Skeet's comment regarding calendar systems and time zones, and I think your premise is fundamentally flawed. Dates aren't better than Calendars. If you're never ever ever going to compare times, or never ever ever have two dates in different time zones, then sure, the smaller footprint can be nice, I guess, but at that point, just use longs and Unix timestamps. Calendars are by far the better object model, and after all, if you absolutely need it, you can get a Date object from it.
If you are stuck having to choose between Date and Calendar when property typing:
Use Calendar if either one of these is true:
You need to be able to adjust the date/time after it is initially set
(such as changing the month while leaving the day and hour the same).
You need to be aware of timezone.
Otherwise, use Date for the following reasons:
Expressing your intentions accurately. If you use Calendar, you are implying that you want a certain functionality that you don't actually intend to use (timezones, changing the day or month, etc).
Less hassle with String representations. For example, consider this class:
public class Reservation {
private Guest guest;
private Calendar dateReserved;
#Override
public String toString() {
return String.format("Reservation{guest=%s,dateReserved=\"%s\"}",
guest, dateReserved);
}
}
Now if you print out an instance of this class, you'll get something hideous:
Reservation{guest=Guest{id=17,name="John Smith"},dateReserved="java.util.GregorianCalendar[time=1426707020619,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=77,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=0,HOUR_OF_DAY=12,MINUTE=30,SECOND=20,MILLISECOND=619,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]"}
Whereas if you had used Date instead, you'd get this:
Reservation{guest=Guest{id=17,name="John Smith"},dateReserved="Wed Mar 18 12:34:26 PDT 2015"}
So if you use Calendar and you want your toString() to be usable, you would need to call dateReserved.getTime() -- which means you'd need to add a null check. This goes for whether or not you end up using a DateFormat object.
Date is a smaller object, quicker to instantiate and with less overhead.
Date is practically immutable -- meaning that the only way to change a date object is to use deprecated methods. So, as said in point 1, expressing your intentions matters. If your date field should be immutable, don't confuse developers who will touch your code in the future by using Calendar (unless of course you need timezone awareness).
"Date" is a more intuitive name than "Calendar" for the type of a field that represents a single point in time.
Date object has fewer fields and occupies less memory than Calendar object and is also faster to instantiate.
I am a college student.
In our college we have to develop a simple Date class in Java similar to the one available in java.util package.
If we do that then what are the methods we can implement in that class,
Since most of the methods are deprecated in original Date class.
I saw the original Date class definitions in java/util/Date.java. Being a beginner to java, I could not understand the concepts of Serializable, Cloneable, Comparable ,and many variables like fasttime.
It will be good if we can implement this date class simply (since we have to develop this code as a test with in 3 hours at lab.)
Whether it is necessary to implement those concepts in a simple Date class.
If I take it as a Project and start developing the whole Date utilities,
then that code will run to many pages
and I cannot finish it with 3 hours for our lab session.
So someone please guide me....
I have doubts about....
Whether it is possible to create a utility class similar to Date class with a simpler implementation.
If we do that, then what are the methods we can implement in that class , since most of the useful methods are deprecated in the original date class.
Thanks in advance.
Serializable means the class can be Serialized to a transportable binary form.
Clonable means the class can be cloned, this is very tricky to get right, mainly because of inheritance and mutability concerns.
Comparable means the class supports being compared to other classes of the same type.
Of these Comparable is the only one that requires any code to function, it is also probably the only one that is any use in your scenario.
Serializable is what is called a Marker Interface it doesn't require any code to cause anything to happen since it doesn't have any methods to implement. It just exists to mark the object as supporting something and another class and check for this interface and do things based on its existence.
Cloneable is something you want to stay away from if at all possible. Cloning objects in Java is not straight forward, has lots of gotchas and generally behaves in the most non-intuitive ways imaginable. If you really want to know about this, learn about this, read this article.
Comparable is very valuable, it lets you compare to like objects to see if one is less than, equal or greater than another. This is a requirement for sorting and Collections classes that support Comparators. Comparators can be thought of as stand alone implementations of Comparable that can be plugged into other classes to control how objects are compared.
java.util.Date is a tricky class, it appears to be a straight forward struct type class with some mutators and convenience methods, but the underlying problem domain for calendar data isn't that simple. Calendar math has lots of exceptional cases. That is why there are so many methods on java.util.Date that are deprecated, they produced wrong behavior in many cases.
For some more code to study, look at this temporal package I developed to wrap the standard Java Calendar with very basic Date, Time and TimeStamp classes, they all just delegate to an instance of Calendar for the actual calcuations.
NOTE: this library code pre-dates JodaTime for those of you that might complain about just not using that library.
You don't have to implement all the interfaces to have a simple working Date class.
I would suggest that you forget about Java's Date class and consider what you think is needed for a date class. For example:
Get/set day of month
Get/set month
Get/set year
Get day of week
toString()
Would give you a pretty good basic date class.
For the sake of completeness, I'll tell you what the interfaces are for. You can decide whether to implement them based on how much you have learned and the assignment's requirements:
Serializable is for saving your object to a stream. You actually don't need to do much work to implement it.
Comparable is for comparing objects (date1.compareTo(date2) should return an integer indicating whether date1 is before, after, or the same as date2).
Clonable is for creating a deep copy of the object.
Since this is a lab project, why don't you list down what kind of function a 'simple' Date class needs and should have. For example, toString() -- returns a string representation of a Data or toMilliSecond() -- returns the number of milliSecond from the reference time.
In Java, an Enum can do the great things that Enums do, but can also have methods (behavior and logic). What advantage does that have over using a class using an enum? Simple examples to illustrate the point would also be welcome.
Here's a simple example:
enum RoundingMode {
UP {
public double round(double d) {
return Math.ceil(d);
}
},
DOWN {
public double round(double d) {
return Math.floor(d);
}
};
public abstract double round(double d);
}
Enum types are also a great way to implement true singletons.
Classic singleton patterns in Java typically involve private constructors and public static factory methods but are still vulnerable to instantiation via reflection or (de-)serialization. An enum type guards against that.
I'm not quite sure where the title of the question fits in with the rest of it. Yes, Java enums have behaviour. They can have state too, although it should really, really be immutable state. (The idea of a mutable enum value is pretty scary IMO.)
An enum in Java is a fixed set of objects, basically. The benefit is that you know that if you have a reference of that type, it's always either null or one of the well-known set.
Personally I really love Java enums and wish C# had them too - they're much more object-oriented than C#'s enums which are basically "named numbers". There are a few "gotchas" in terms of initialization order, but they're generally fab.
Because the enum instances are singletons, you can use them in switch statements or with == to check equality.
Basically, Java enums are classes (I don't believe there is a difference at the bytecode level), with the additional benefit of having a known fixed set of possible instances and being able to use them in switch statements.
You can emulate the "known fixed set of possible instances" with regular classes (the "typesafe enum" pattern described in countless books and articles), but it's quite some work (repeated for every such class) to get it to work really correctly in regard to Serialization, equals() and hashCode(), and perhaps some other things I forgot. Language-level enums spare you that work. And, as mentioned above, only language-level enums can be used in switch statements.
In our project, we're using Enums for a few things, but perhaps most prominently for i18n purposes - each piece of shown text is given an Enum. The Enum class has a String-returning method that inspects the Locale that is being used, and picks the correct translation from a collection of translations on runtime.
This serves as a dual-purpose - you get code completion from your IDE, and also never forget to translate a string.
The usage is very simple, to the point that it's almost rendundant to give an example, but here's how one might use the translation-enum
System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName());
Or, if you want to be fancy, have the Enum accept arguments, which will, with some magic string manipulation, be inserted in a marked position in the translations string
System.out.println(Translations.GREET_PERSON.trans(user.getName());
Take a look at java/joda time classes, where enums do hell of a lot of job.
Here is an example of java.time.Month:
public enum Month implements TemporalAccessor, TemporalAdjuster {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
private static final Month[] ENUMS = Month.values();
public static Month of(int month) {
if (month < 1 || month > 12) {
throw new DateTimeException("Invalid value for MonthOfYear: " + month);
}
return ENUMS[month - 1];
}
// About a dozen of other useful methods go here
}