So I am trying to create a program that helps me keep track of my expenses and i have a question to do with how I create my objects.
So far i have been creating my objects like so:
Grocery milk = new Grocery();
milk.setName("Milk");
milk.setCost(2.84);
milk.setDate(30, 12, 2014);
milk.setType("Food");
My grocery class extends this expense class:
public Expense(){}
public Expense(String name, Double cost, Calendar purchaseDate){
name = _name;
cost = _cost;
purchaseDate = _purchaseDate;
}
So far my grocery class only adds another string parameter that i call type, and so here is my question:
Instead of using set methods to set my paramters for each new created object i would like to do it like this:
Grocery milk = new Grocery("Milk", 2.84, ??Date??, "Food")
But the date parameter is a little more complicated than the other parameters that are just of type string and double, is there a way to do what I want or am i better off using the set methods?
Thanks in advance for any help.
You can simply use an Object of type Date
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
Date date = formatter.parse("16/01/2015");
Grocery milk = new Grocery("Milk", 2.84, date, "Food")
Alternatives include using a Calendar object (which has more flexible/powerful date manipulation methods), or just storing your date as a String.
As for deciding whether you should use setX() methods or using a comprehensive constructor, unless there is a reason not to you can just have both available, and just use the most suitable at any one time.
Further reading:
Official Java Date & Time tutorials
Official Java Calendar tutorials
Related
Im learning object oriented programming in school right now, and there are some aspects of it I don't quite understand yet. I have a program that creates a database of users with their names, and birthdates. So I have 3 classes: person, PersonProgram(the main), and Date. The Person class has the constructor, setter, and getters for the names and the birth date. The Date class has error checking for proper dates and leap years etc. In the main program I create 5 People, and then give menu options to change and modify the names and dates. So for example, if the user wants to change the name my code looks like this:
System.out.println("Enter new first name:");
people[choice-1].setFirstName(input.next());
and that works and makes sense to me. But I want to know how I can change the date properly? The Date constructor takes 3 integers for the day, year, and month, so in the main program I prompt the user to input the 3 new dateswhich are stored in day, month, year integers. So my understanding is from there I would pass those 3 integers to the Date constructor:
new Date(month, day, year);
What I am confused on is where to go from there. The Date constructor gets the new Date call, and passes it to the setters. How can this newly created date object be passed back to the Person program, so the setter in Person for the birthdate can update the corresponding Person object? If I am not clear on my question please let me know, I figured I could articulate what I am trying to ask without posting all my code.
In your Person class you should have something like this:
public class Person {
private Date birthDate;
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate){
this.birthDate = birthDate;
}
}
And then in you would set the birthDate like:
person[choice-1].setBirthDate(new Date(month,day,year));
Taking into consideration that you are starting with OOP there is an important concept here, Encapsulation, the Person class restricts the free access to its fields, like birthDate, and sets the rules for the interaction with them. As an example you could check if the date is null before assigning it.
public void setBirthDate(Date birthDate){
if(birthDate != null) {
this.birthDate = birthDate;
} else {
//Whatever you wanna do here (throw an Exception, etc, etc)
}
}
Comment Question
Although it would be better to create another question:
Do I have to create an instance of the Date class in my Person class? Or anywhere for that matter?
No, the property/field birthDate is a reference to a Date object which will be stored in memory until no references are left. And it's up to you where to create them, nonetheless there are Creational Patterns, a familiy of Design Patterns that help you with this matter.
is it the birth date in person class of type 'Date'?
if so, you should create an instance of your class Date , do the control that you need and pass it to the constructor or setter of the birth date in the persson instance .
Date birthDate = new Date(month, day, year);
// Some controls
people[choice-1].setBirthDate(birthDate);
Date the_birth_date = new Date(mounth, day, year);
people[choice - 1].setBirthDate(the_birth_date);
You can set it like this: people[choice-1].setBirthday(new Date(month, day, year));. You would have to give the option to select the Person first.
I have a post that describes the class structure a
enum static variable reference between java but as I began finishing up testing I'm running into a trivial error where I create the ArrayList but the debug statement show me that the Class Object is either the new list item created or the constructor default values.
#Test
public GoodsTest()
clearProductMaps();
Goods item = new Goods();
calendar.set(Calendar.MONTH, Calendar.JULY);
calendar.set(Calendar.DAY_OF_MONTH, 21);
calendar.set(Calendar.YEAR, 2016);
date = calendar.getTime();
item.setName("FirstItem_A");
item.setPrice(4.10);
item.setStatus(Library.STATUSES.US);
item.setDate(date);
actualGoods.add(0,item);
item = new Goods();
item.setProductName("FirstItem_A");
item.setPrice(3.70);
item.setStatus(Library.STATUSES.ME);
calendar.set(Calendar.MONTH, Calendar.AUGUST);
date = calendar.getTime();
item.setDate(date);
actualGoods.add(item);
System.out.println("debug " + actualGoods.get(0).getStatus());
}
My clearProductMaps just mandates the List is empty for the test.
The print statement is : debug ME
when I am expected the statement to be : debug US
Evidently setStatus of both different Goods seem to write to the same field. So this field is static. Static fields are fields of the class object Good.
As you spoke of enum, every enum constant is a static global singleton too.
enum Status {
SLEEPY,
ENERGETIC;
public int coffee;
}
Now the two objects each have a single coffee. Assigning it would be valid for either all SLEEPY or ENERGETIC occurrences. Such a confusion seems to be the case with Library.STATUSES.ME/US.
In my application, I have to instantiate many different types of objects. Each type contains some fields and needs to be added to a containing type. How can I do this in an elegant way?
My current initialization step looks something like this:
public void testRequest() {
//All these below used classes are generated classes from xsd schema file.
CheckRequest checkRequest = new CheckRequest();
Offers offers = new Offers();
Offer offer = new Offer();
HotelOnly hotelOnly = new HotelOnly();
Hotel hotel = new Hotel();
Hotels hotels = new Hotels();
Touroperator touroperator = new Touroperator();
Provider provider = new Provider();
Rooms rooms = new Rooms();
Room room = new Room();
PersonAssignments personAssignments = new PersonAssignments();
PersonAssignment personAssignment = new PersonAssignment();
Persons persons = new Persons();
Person person = new Person();
Amounts amounts = new Amounts();
offers.getOffer().add(offer);
offer.setHotelOnly(hotelOnly);
room.setRoomCode("roomcode");
rooms.getRoom().add(room);
hotels.getHotel().add(hotel);
hotel.setRooms(rooms);
hotelOnly.setHotels(hotels);
checkRequest.setOffers(offers);
// ...and so on and so on
}
I really want to avoid writing code like this, because it's a little messy having to instantiate each object separately and then initialize each field across multiple lines of code (e.g. having to call new Offer() and then setHotelOnly(hotelOnly) and then add(offer)).
What elegant methods can I use instead of what I have? Are there any "Factories" that can be used? Do you have any references/examples to avoid writing code like this?
I'm really interested in implementing clean code.
Context:
I'm developing a RestClient Application for sending post requests to a Webservice.
The API is represented as a xsd schema file and I created all the Objects with JAXB
Before sending a request I have to instantiate many Objects because they have dependencies with each other.
(An Offer has Hotels, a Hotel has Rooms, a Room has Persons... And these Classes are the generated ones)
Thanks for your help.
You can either use a constructor or a builder pattern or a variation of the builder pattern to fix the problem of having too many fields in your initialization step.
I'm going to extend your example a bit to prove my point of why these options are useful.
Understanding your example:
Lets say an Offer is simply a container class for 4 fields:
public class Offer {
private int price;
private Date dateOfOffer;
private double duration;
private HotelOnly hotelOnly;
// etc. for as many or as few fields as you need
public int getPrice() {
return price;
}
public Date getDateOfOffer() {
return dateOfOffer;
}
// etc.
}
As it stands in your example, to set values to these fields, you use setters:
public void setHotelOnly(HotelOnly hotelOnly) {
this.hotelOnly = hotelOnly;
}
Unfortunately, this means if you need an offer with values in all of the fields, you have to do what you have:
Offers offers = new Offers();
Offer offer = new Offer();
offer.setPrice(price);
offer.setDateOfOffer(date);
offer.setDuration(duration);
offer.setHotelOnly(hotelOnly);
offers.add(offer);
Now let's look at improving this.
Option 1: Constructors!
A constructor other than the default constructor (the default constructor is currently Offer() ) is useful for initializing the values of the fields in your class.
A version of Offer using constructors would look like this:
public class Offer {
private int price;
private Date dateOfOffer;
//etc.
// CONSTRUCTOR
public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
this.price = price;
this.dateOfOffer = dateOfOffer;
//etc.
}
// Your getters and/or setters
}
Now, we can initialize it in one line!
Offers offers = new Offers();
Offer offer = new Offer(price, date, duration, hotelOnly);
offers.add(offer);
Even better, if you never use offer other than that single line: offers.add(offer); you don't even need to save it in a variable!
Offers offers = new Offers();
offers.add( new Offer(price, date, duration, hotelOnly) ); // Works the same as above
Option 2: Builder Pattern
A builder pattern is useful if you want the option of having default values for any of your fields.
The problem a builder pattern solves is the following messy code:
public class Offer {
private int price;
private Date dateOfOffer;
// etc.
// The original constructor. Sets all the fields to the specified values
public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
this.price = price;
this.dateOfOffer = dateOfOffer;
// etc.
}
// A constructor that uses default values for all of the fields
public Offer() {
// Calls the top constructor with default values
this(100, new Date("10-13-2015"), 14.5, new HotelOnly());
}
// A constructor that uses default values for all of the fields except price
public Offer(int price) {
// Calls the top constructor with default values, except price
this(price, new Date("10-13-2015"), 14.5, new HotelOnly());
}
// A constructor that uses default values for all of the fields except Date and HotelOnly
public Offer(Date date, HotelOnly hotelOnly) {
this(100, date, 14.5, hotelOnly);
}
// A bunch more constructors of different combinations of default and specified values
}
See how messy that can get?
The builder pattern is another class that you put inside your class.
public class Offer {
private int price;
// etc.
public Offer(int price, ...) {
// Same from above
}
public static class OfferBuilder {
private int buildPrice = 100;
private Date buildDate = new Date("10-13-2015");
// etc. Initialize all these new "build" fields with default values
public OfferBuilder setPrice(int price) {
// Overrides the default value
this.buildPrice = price;
// Why this is here will become evident later
return this;
}
public OfferBuilder setDateOfOffer(Date date) {
this.buildDate = date;
return this;
}
// etc. for each field
public Offer build() {
// Builds an offer with whatever values are stored
return new Offer(price, date, duration, hotelOnly);
}
}
}
Now, you can not have to have so many constructors, but still are able to choose which values you want to leave default, and which you want to initialize.
Offers offers = new Offers();
offers.add(new OfferBuilder().setPrice(20).setHotelOnly(hotelOnly).build());
offers.add(new OfferBuilder().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200).build());
offers.add(new OfferBuilder().build());
That last offer is simply one with all default values. The others are default values except the ones that I set.
See how that makes things easier?
Option 3: Variation of Builder Pattern
You can also use the builder pattern by simply making your current setters return the same Offer object. It's exactly the same, except without the extra OfferBuilder class.
Warning: As user WW states below, this option breaks JavaBeans - a standard programming convention for container classes such as Offer. So, you shouldn't use this for professional purposes, and should limit your use in your own practices.
public class Offer {
private int price = 100;
private Date date = new Date("10-13-2015");
// etc. Initialize with default values
// Don't make any constructors
// Have a getter for each field
public int getPrice() {
return price;
}
// Make your setters return the same object
public Offer setPrice(int price) {
// The same structure as in the builder class
this.price = price;
return this;
}
// etc. for each field
// No need for OfferBuilder class or build() method
}
And your new initialization code is
Offers offers = new Offers();
offers.add(new Offer().setPrice(20).setHotelOnly(hotelOnly));
offers.add(new Offer().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200));
offers.add(new Offer());
That last offer is simply one with all default values. The others are default values except the ones that I set.
So, while it's a lot of work, if you want to clean up your initialization step, you need to use one of these options for each of your classes that have fields in them. Then use the initialization methods that I included with each method.
Good luck! Does any of this need further explanation?
I've always preferred using builder-pattern-with-a-twist because it provides much more than the basic approach of the builder pattern.
But what happens when you want to tell the user that she must call one builder method or the other, since it is crucial for the class you’re trying to build.
Think about a builder for a URL component. How would one think about the builder methods for encapsulating access to URL attributes, are they equally important, do they interact with each other, etc? While the query parameters or fragment are optional the hostname is not; you could say that protocol is also required but for that you can have a meaningful default, like http right?
Anyway, I don't know if this makes sense to your particular problem but I thought it would be worth mentioning for others to have a look at it.
Some nice answeres are already given here!
What came to my mind as an addition is Domain Driven Design. Specific the Building blocks part, with Entity, Value Object, Aggregate, Factory etc.
A nice introduction is given in Domain Driven Design - Quickly (pdf).
I just provide this answer because it was mentioned in a comment and I think it should also be a part of this enumeration of Design Patterns.
Null Object Design Pattern
Intent
The intent of a Null Object is to encapsulate the absence of an object by providing a substitutable alternative that offers suitable default do nothing behavior. In short, a design where "nothing will come of nothing"
Use the Null Object pattern when
an object requires a collaborator. The Null Object pattern does not introduce this collaboration--it makes use of a collaboration that already exists
some collaborator instances should do nothing
you want to abstract the handling of null away from the client
Here you find the full part of "Null Object" Design Pattern
Ideally, an object should not be concerned about instantiating its dependencies. It should only worry about things that it is supposed to do with them.
Have you considered any dependency injection framework? Spring or Google's Juice are quite versatile and have a small footprint.
The idea is simple, you declare the dependencies and let the framework decide when/how/where to create them and 'inject' it into your classes.
If you don't want to use any framework, you can take design notes from them and try to emulate their design patterns and tweak it for your use-case.
Also, you can simplify things to a certain extent by making proper use of Collections. For example, what additional feature does Offers have other than storing a collection of Offer? I'm not sure what your constraints there are but, if you can make that part a bit more cleaner you would have massive gains in all places where you are instantiating the objects.
Dozer framework provides nice way to do copy values from ws object to your dto. Here is another example. Additionally if the getter/setter names are the same of both class you dont need custom converter
I want to save several periods of time, which look like that:
public class periodOfTime {
Date from;
Date to;
}
into a List, which looks like that
List <periodOfTime> periodsOfTime = new List<periodOfTime>()
right now.
How can I store !FOR EXAMPLE!
Date s = new Date();
in my list?
My thoughts were, that it can be done with
periodsOfTime.add(s,s)
But it keeps on telling me
The method add(int, periodOfTime) in the type List is not applicable for the arguments (Date, Date)
Can anyone guide me?
Probably I am totally blind right now....
You may want to make getters and setters:)
Try:
PeriodOfTime period = new Period();
period.from = date;
period.to = another_date;
and add to for example ArrayList:
periodsOfTime.add(period);
It will help.
I have a code where a Student Object is created and depending on its time has to move from one list to another, therefore I need to timestamp those objects to know when they were created
class Student
{
private Date creationDate = new Date();
public Date getCreationDate()
{
return new Date(creationDate.getTime());
}
}
Initialize an instance variable with the current time in the constructor.
The code that created it can then interrogate the new instance and move it to the appropriate list.
If the creation time only matters once, don't even use an instance variable, just get the current time when you create it and act accordingly.
System.currentTimeMillis() returns the current time in milliseconds.