I was reading this article on why getter and setters are evil. The article doesn't say not to use them ever, but, it's telling you to think in a way that limits the use of those methods, or to quote the article:
Don't ask for the information you need to do the work; ask the object
that has the information to do the work for you.
what happens when you need to display data in a GUI, but don't have getter methods? The article covers this briefly, but not fully. It mentions passing a JComponent to the class, but if you're GUI changes, it could lead to a lot of work to fix.
Take for example, you have a Book class (making this example limited to keep it readable).
public final class Book {
private String title;
//Authors is class with the attributes authorFirstname, authorLastname
private List<Author> listofAuthors;
public Book(String title, List<Author> listofAuthors)
{
//initialization
}
//other methods that do work
}
If I have a GUI that has a JTextField to display the book title and a JTable to display the list of authors, how would I write my method to "do the work" for me and display the result? Is this one of those times where a getter is necessary?
Allen Holub's article (the one you mentioned) is completely right, you shouldn't ask for data, at least when you're doing Object-Orientation. And no, displaying things is not a valid excuse to open up an object.
If you have a Book, just ask for the Book to display itself! It shouldn't matter whether that uses a JTextField or JTable or whatever. Depending on your requirements of course, you could do:
public final class Book {
...
JComponent display() {
...
}
}
The point of Object-Orientation is of course, that you are trying to localize changes (restrict to one class as much as possible). The only way to do that is to localize the functionality that depends on the same things into (preferably) the same class. Also called increasing "cohesion".
So now, if the Book internals change, all of the things, including how the Book is displayed is in the Book itself, so there is no need to "hunt" for code that uses the Book.
Now, for the answer that this is not "clean", because you are mixing presentation code with "business logic". It may be interesting to note, that the whole idea of not mixing presentation with "business logic" comes from earlier times, when we still thought that presentation might be "remote" to the "business objects", where "business objects" might be used by multiple applications for different things. Ie. multi-tier designs. YAGNI. Most of the time there is no real reason to have artificial technical boundaries inside a single application. There is no harm done if the Book knows it's part of a GUI application, and there are real benefits (maintainability) to have.
Edit: this is how the `display() method could look like in detail, with displaying the title and authors (pseudocode for Swing):
public final class Book {
private final String title;
private final List<Author> authors;
...
public JComponent display() {
JPanel bookPanel = new JPanel();
bookPanel.add(new JLabel(title));
JList authorsList = new JList(); // Or similar
for (Author author: authors) {
authorsList.add(author.display());
}
bookPanel.add(authorsList);
return bookPanel;
}
}
And then you can simply add() that component to whatever swing container you want to display the book in.
Think of it this way: Getters (public functions) are a bridge for private attributes.
I'll write you a simple example to modify your TextField using OOP.
Book class:
public final class Book {
private String title;
//Authors is class with the attributes authorFirstname, authorLastname
private List<Author> listofAuthors;
public Book(String title, List<Author> listofAuthors)
{
//initialization
}
public String getTitle() {
return this.title; }
}
GUI:
author1 = new Author("jhon");
author 2 = new Author("alsojhon");
list = new ArrayList();
list.add(author1);
list.add(author2)
b = new Book("stack",list);
JTextField field;
field.setText(b.getTitle());
You can create three kind of classes:
Entity, classes that represents a business concept and have only one unique id, like Client class with Id the username. It is usually a mutable class. You should have all the business logic here. You should not open his data with getters and setters.
Value object, classes that represents a business concept but not have an unique id, like Email class. It is usually an imm.utable class. You should have all the business logic here.
Data structure (kind of DTO), classes to save data only, without behavior, maybe you have setters and getters to access those datas.
What can I do if I need to access all Client data if I do not have accesors? Well, you should transform Client to a DTO. You can use a framework like Orika. Or you can create a method into Client class to ask for information (mediator pattern).
I like second option but it implies more work:
class Client{
private String name;
...
public void publishInfo(ClientInfo c){
c.setName(name);
...
}
}
class ClientInfo{
private String name;
//GETTERS
//SETTERS
}
Are you asking about a method to display all the information for you? I'm not following.
If that is what you're asking, here's my recommendation: Don't write it in the class with the window code in it. It won't be very clean. Make a new class with that method in it (Yes, getters are necessary, they make OOP easier, but that's biased).
What I do if I want to iterate through a list is make a StringBuilder, along with a for loop, that adds the name of the author. Then, have the method return the list of authors.
List<Authors> a;
StringBuilder d = new StringBuilder();
for (int i = 0; i < a.size(); i++) {
d.append(a.get(i).getName() + ", ");
}
return d.toString();
//It's just sudo code, but still.
Related
I have a list of car manufacturers, models, and trims. Each of those objects has different attributes on them. Ex. car makers can have import vs domestic, sport vs luxery, etc. My current setup looks something like below,
public Manufacturer {
private String manufacturerName; //Getter&Setter as well
private List<Model> modelList; //Getter&Setter as well
//additional attributes
}
public Model {
private String modelName;
private List<Trim> trimList; //Getter&Setter as well
//additional attributes
}
public Trim {
private String trimType; //Getter&Setter as well
//additional attributes
}
public ContainerClass {
public List<Manufacturer> manufacturerList;
}
Now I can create the objects as Mazda, 3, Grand Touring and associate the objects in the list. But if someone comes along and just wants a car that has a sunroof, it feels like a waste to have to dig into every possible manufacturer and every model for that manufacturer to see if the trim has a sunroof attribute. Are there any strategies I could use to make this easier for developers, including myself?
Note: I am at a point where I don't have a database because I don't have real data to fill the database, this is a stop gap until I get that data later, so please don't just say "create a database" :). Also I am loading this information from an ExamplesTable object of JBehave.
You can filter the manufacturers by some sub-streams:
container.getManufacturerList().stream()
.filter(manufacturer ->
manufacturer.getModelList().stream().anyMatch(model ->
model.getTrimList().stream().anyMatch(trim ->
trim.getTrimType().equals("sunroof"))))
.collect(Collectors.toList());
I am relatively new to Java. I have been struggling to define a class that meets my needs. Searching on this site or google did not have probably because the question is so specific. Any help is appreciated!
Ideally the class (lets call it Filer) would have:
Name (string)
Volumes (Collection/list of Strings: 0 -100)
Each Volume, in turn, will have:
A. Name (string)
B. Servers_Permed (another collection/list of Strings: 0-40)
Once I can get the class defined, I will do ok with defining getters and setters to use it, but so far I have failed to defined the class without getting totally lost :-)
Thanks!
It seams that your description is not correct.
You need a class Filer with:
name (String)
volumes (list of Volume) (not strings as you asked, because you explained differently on the second part of the question, it is evident that you need a list of Volume and not a list of String)
And a second class Volume with:
Name (string)
Servers_Permed (list of strings)
So you need a data structure like the following:
public class Volume {
private String name;
private List<String> serversPermed; // Changed the name to a name more adherent to standard guidelines
...
}
public class Filer {
private String name;
private List<Volume> volumes;
...
}
well, lay it out piece by piece.
First, you have Volume (not sure how volumes could be "Collection/list of Strings: 0 -100" and have the following properties):
public class Volume {
String name;
List<String> servers_permed;
}
Now you have Filer:
public class Filer {
String name;
List<Volume> volumes;
}
you will have to add the necessary constructors, getters/setters.
Both of the answer given above worked beautifully (they are almost the same anyway).
Thank you, Davide and DBug!
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 have seen constructs with an enum declared inside an enum. What is this used for ?
Enums in Java can't be extended, so if you wanna collate strongly-related enums in one place you can use these nested enum constructs. For example:
public enum DepartmentsAndFaculties
{
UN (null, "UN", "University"),
EF (UN, "EF", "Engineering Faculty"),
CS (EF, "CS", "Computer Science & Engineering"),
EE (EF, "EE", "Electrical Engineering");
private final DepartmentsAndFaculties parent;
private final String code, title;
DepartmentsAndFaculties(DepartmentsAndFaculties parent, String code, String title)
{
this.parent = parent;
this.code = code;
this.title = title;
}
public DepartmentsAndFaculties getParent()
{
return parent;
}
public String getCode()
{
return code;
}
public String getTitle()
{
return title;
}
}
Here, inner enums consist of {parent enum, code, title} combinations. Example usage:
DepartmentsAndFaculties cs = DepartmentsAndFaculties.CS;
cs.getTitle();
You can see the power of nested enums when constructing hierarchical entities/enums.
You might mean an Enum as an inner type. This is most typically seen when the outer type is a class or an interface, but I suppose there isn't any reason this couldn't be done with enum as an outer.
Inner types are partly about code organization. They can be useful in avoiding creating a bunch of separate files when you have a few types that are related. Sometimes it can make type name more intuitive. For instance, see Map class and its inner Entry class. Most external references to Entry would use Map.Entry format, which is very readable.
The other reason for inner types is that if outer type is a class or an enum, then inner type can be non-public. This is useful for hiding types that are implementation details of the outer type.
I have used nested enums in rare cases where I wanted to enforce a naming convention on the enum values, if additions of new names would have implications for operations or other folks. Here's one example:
public enum MessageTemplateName {
account_verify,
vendor_job_request,
account_job_confirmed,
vendor_job_confirmed,
account_friend_request,
account_job_accepted,
vendor_job_accepted_by_other;
/** Make sure you tell operations if you're adding a new recipient */
private enum Recipient { account, vendor }
private Recipient recipient;
private String messageName;
MessageTemplateName () {
final int firstUnderscore = name().indexOf('_');
recipient = Recipient.valueOf(name().substring(0, firstUnderscore));
messageName = name().substring(firstUnderscore+1);
}
public String getTemplateUrl (String baseUrl) {
if (!baseUrl.endsWith("/")) baseUrl += "/";
return baseUrl + recipient.name() + "/" + messageName + ".vm";
}
}
I'm using an Enum because I want to be able to pass around a generic "message template name" in various places. As you can see, the first part of the enum name corresponds to a directory on a server, and the remainder of the name refers to a Velocity template file name. If fellow engineers started introducing new constants, I'd want to make sure they were filed under the appropriate "recipient", or if a new recipient legitimately needs to be created, that it's a conscious effort to do so, and you'll inform operations (create the directory in production, put any monitoring/permissions in place, etc).
There's a decent argument that, if at some point your Enum becomes too complex, you can replace it with a class/class hierarchy coupled with a much simpler enum. Not sure where I draw the line, but I suppose the above is heading in that direction.
I'm struggling to come up with a good way of adding a bidirectional relation in OO model. Let's say there is a Customer who can place many Orders, that is to say there is a one-to-many association between Customer and Order classes that need to be traversable in both directions: for a particular customer it should be possible to tell all orders they have placed, for an order it should be possible to tell the customer.
Here is a snippet of Java code, although the question is largely language-agnostic:
class Customer {
private Set orders = new HashSet<Order> ();
public void placeOrder (Order o) {
orders.add(o);
o.setCustomer(this);
}
}
class Order {
private Customer customer;
public void setCustomer (Customer c) {
customer = c;
}
}
What buggers me is that given the model someone could easily call:
o.setCustomer(c);
instead of correct
c.placeOrder(o);
forming unidirectional link instead of bidirectional one.
Still learning OOP, could anyone please help with what would be an idiomatic and practical way of solving this problem without resorting to "reflection" or fancy frameworks (that would anyway rely on reflection).
P.S. There is a similar question: Managing bidirectional associations in my java model, however I don't feel it answers my plea.
P.S.S. Any links to source code of real-life projects implementing business model on top of db4o are greatly appreciated!
This is a very interesting question, which has profound implications on the theory and practice of OOP. First I will tell you the quick and dirty way to (almost) accomplish what you requested. In general I don't recommend this solution, but since nobody mentioned it and (if memory doesn't fail me) it is mentioned in a book from Martin Fowler (UML Distilled), it is probably worth talking about; you can change the definition of the setCustomer method from:
public void setCustomer (Customer c) {
customer = c;
}
to:
void setCustomer (Customer c) {
customer = c;
}
and make sure Customer and Order are in the same package. If you don't specify an access modifier, setCustomer defaults to package visibility, which means it will be only accessible from classes within the same package. Obviously this does not protect you from illegitimate access from classes other than Customer within the same package. Also, your code will break if you decide to move Customer and Order in two different packages.
Package visibility is largely tolerated in common programming practice in Java; I feel like within the C++ community the friend modifier is not as tolerated as package visibility in Java, despite the fact that it serves a similar purpose. I can't really understand why, because friend is much more selective: basically for each class you can specify other friend classes and functions which will be able to access the private members of the first class.
However, there are no doubts that neither Java's package visibility nor C++'s friend are good representatives of what OOP means, and not even of what Object-Based Programming means (OOP is basically OBP plus inheritance and polymorphism; I'll use the term OOP from now on). The core aspect of OOP is that there are entities called objects, and they communicate by sending messages to each other. Objects have an internal state, but this state can only be altered by the object itself. State is typically structured i.e. it is basically a collection of fields such as name, age and orders. In most languages messages are synchronous and they can't be dropped by mistake, like a mail or a UDP packet. When you write c.placeOrder(o) it means that sender, which is this, is sending a message to c. The contents of this message are placeOrder and o.
When an object receives a message it must handle it. Java, C++, C# and a lot of other languages assume that an object can handle a message only if its class defines a method with an appropriate name and list of formal parameters. The set of the methods of a class is called its interface, and languages such as Java and C# also have an appropriate construct, namely interface to model the concept of a set of methods. The handler for the message c.placeOrder(o) is the method:
public void placeOrder(Order o) {
orders.add(o);
o.setCustomer(this);
}
The body of the method is where you write the instructions that will alter the state of object c, if necessary. In this example the orders field is modified.
This is, in essence, what OOP means. OOP was developed in the context of simulations, in which you basically have a lot of black boxes that communicate with each other, and each box is responsible for its own internal state.
Most modern languages adhere perfectly to this scheme, but only if you restrict yourself to private fields and public/protected methods. There are a few gotchas, though. For instance, within a method of class Customer you could access the private fields, such as orders, of another Customer object.
The two answers on the page you linked are actually very good, and I upvoted both. However, I think, it is completely reasonable with respect to OOP, to have a real bidirectional association, as you described. The reason is that to send a message to someone, you must have a reference to him. That is why I'll try to outline what the problem is, and why we OOP programmers sometimes struggle with this. Long story short, real OOP is sometimes tedious, and very akin to a complex formal method. But it produces code that is easier to read, modify and extend, and in general saves you from a lot of headaches. I've been wanting to write this down for a while, and I think your question is a good excuse to do it.
The main problem with OOP techniques arises whenever a group of object must alter the internal state simultaneously, as a result of an external request, dictated by business logic. For instance, when a person is hired, lots of stuff happen. 1) The employee must be configured to point to his department; 2) he must be added to the list of hired employees in the department; 3) something else must be added somewhere else, like a copy of the contract (maybe even a scan of it), insurance information and so on. The first two actions that I cited are exactly an example of establishing (and maintaining, when the employee is fired or transferred) a bidirectional association, like the one you described between customers and orders.
In procedural programming Person, Department and Contract would be structures, and a global procedure like hirePersonInDepartmentWithContract associated to the click of a button in an user interface would manipulate 3 instances of these structures by the means of three pointers. The entire business logic is inside this function, and it must take into consideration every possible special case while updating the state of these three objects. For instance, there is the possibility that when you click the button to hire someone, he is already employed in another department, or even worse in the same. And computer scientists know that special cases are bad. Hiring a person is basically a very complex use case, with lots of extensions which don't happen very often, but that must be considered.
Real OOP mandates instead that objects must exchange messages to accomplish this task. The business logic is split among the responsibilities of several objects. CRC cards are an informal tool to study business logic in OOP.
To get from the valid state where John is unemployed, to the other valid state where he is a project manager at the R&D department, it is necessary to go through a number of invalid states, at least one. So there is an initial state, an invalid state and a final state, and at least two messages exchanged between a person and a department. You can also be sure that one message must be received by the department, to give it a chance of altering its internal state, and another one must be received by the person, for the same reason. The middle state is invalid in the sense that it doesn't really exist in the real world, or maybe exists but is of no importance. However, the logical model in your application must in a way keep track of it.
Basically the idea is that when the human resource guy fills the "New Employee" JFrame and clicks the "Hire" JButton, the selected department is retrieved from a JComboBox, which in turn may have been populated from a database, and a new Person is created based on the information inside the various JComponents. Maybe a job contract is created containing at least the name of the position and the salary. Finally there is appropriate business logic that wires all the objects together and triggers updates for all the states. This business logic is triggered by a method called hire defined in class Department, which takes as arguments a Person and a Contract. All of this may happen in the ActionListener of the JButton.
Department department = (Department)cbDepartment.getSelectedItem();
Person person = new Person(tfFirstName.getText(), tfLastName.getText());
Contract contract = new Contract(tfPositionName.getText(), Integer.parseInt(tfSalary.getText()));
department.hire(person, contract);
I would like to stress what's going on at line 4, in OOP terms; this (which in our case is the ActionListener, is sending a message to department, saying they must hire person under contract. Let's have a look at a plausible implementation of these three classes.
Contract is a very simple class.
package com.example.payroll.domain;
public class Contract {
private String mPositionName;
private int mSalary;
public Contract(String positionName, int salary) {
mPositionName = positionName;
mSalary = salary;
}
public String getPositionName() {
return mPositionName;
}
public int getSalary() {
return mSalary;
}
/*
Not much business logic here. You can think
about a contract as a very simple, immutable type,
whose state doesn't change and that can't really
answer to any message, like a piece of paper.
*/
}
Person is way more interesting.
package com.example.payroll.domain;
public class Person {
private String mFirstName;
private String mLastName;
private Department mDepartment;
private boolean mResigning;
public Person(String firstName, String lastName) {
mFirstName = firstName;
mLastName = lastName;
mDepartment = null;
mResigning = false;
}
public String getFirstName() {
return mFirstName;
}
public String getLastName() {
return mLastName;
}
public Department getDepartment() {
return mDepartment;
}
public boolean isResigning() {
return mResigning;
}
// ========== Business logic ==========
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
resign();
mDepartment = department;
}
public void youAreFired() {
assert(mDepartment != null);
assert(mDepartment.isBeingFired(this));
mDepartment = null;
}
public void resign() {
assert(mDepartment != null);
mResigning = true;
mDepartment.iResign(this);
mDepartment = null;
mResigning = false;
}
}
Department is quite cool.
package com.example.payroll.domain;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Department {
private String mName;
private Map<Person, Contract> mEmployees;
private Person mBeingHired;
private Person mBeingFired;
public Department(String name) {
mName = name;
mEmployees = new HashMap<Person, Contract>();
mBeingHired = null;
mBeingFired = null;
}
public String getName() {
return mName;
}
public Collection<Person> getEmployees() {
return mEmployees.keySet();
}
public Contract getContract(Person employee) {
return mEmployees.get(employee);
}
// ========== Business logic ==========
public boolean isBeingHired(Person person) {
return mBeingHired == person;
}
public boolean isBeingFired(Person person) {
return mBeingFired == person;
}
public void hire(Person person, Contract contract) {
assert(!mEmployees.containsKey(person));
assert(!mEmployees.containsValue(contract));
mBeingHired = person;
mBeingHired.youAreHired(this);
mEmployees.put(mBeingHired, contract);
mBeingHired = null;
}
public void fire(Person person) {
assert(mEmployees.containsKey(person));
mBeingFired = person;
mBeingFired.youAreFired();
mEmployees.remove(mBeingFired);
mBeingFired = null;
}
public void iResign(Person employee) {
assert(mEmployees.containsKey(employee));
assert(employee.isResigning());
mEmployees.remove(employee);
}
}
The messages I defined have, at the very least, very pittoresque names; in a real application you might not want to use names like these, but in the context of this example they help to model the interactions between objects in a meaningful and intuitive way.
Department can receive the following messages:
isBeingHired: the sender wants to know whether a particular person is in the process of being hired by the department.
isBeingFired: the sender wants to know whether a particular person is in the process of being fired by the department.
hire: the sender wants the department to hire a person with a specified contract.
fire: the sender wants the department to fire an employee.
iResign: the sender is likely an employee, and is telling the department that he is resigning.
Person can receive the following messages:
youAreHired: the department sends this message to inform the person that he is hired.
youAreFired: the department sends this message to inform the employee that he is fired.
resign: the sender wants the person to resign from his current position. Note that an employee who was hired by another department can send the resign message to himself in order to quit the old job.
The fields Person.mResigning, Department.isBeingHired, Department.isBeingFired are what I use to encode the aforementioned invalid states: when either one of them is "non-zero", the application is in an invalid state, but is on its way to a valid one.
Also note that there are no set methods; this contrasts with the common practice of working with JavaBeans. JavaBeans are in essence very similar to C structures, because they tend to have a set/get (or set/is for boolean) pair for every private property. However they do allow for validation of set, for instance you can check that a String being passed to a set method is not-null and not empty and eventually raise an exception.
I wrote this little library in less than a hour. Then I wrote a driver program and it worked correctly with the JVM -ea switch (enable assertions) at the very first run.
package com.example.payroll;
import com.example.payroll.domain.*;
public class App {
private static Department resAndDev;
private static Department production;
private static Department[] departments;
static {
resAndDev = new Department("Research & Development");
production = new Department("Production");
departments = new Department[] {resAndDev, production};
}
public static void main(String[] args) {
Person person = new Person("John", "Smith");
printEmployees();
resAndDev.hire(person, new Contract("Project Manager", 3270));
printEmployees();
production.hire(person, new Contract("Quality Control Analyst", 3680));
printEmployees();
production.fire(person);
printEmployees();
}
private static void printEmployees() {
for (Department department : departments) {
System.out.println(String.format("Department: %s", department.getName()));
for (Person employee : department.getEmployees()) {
Contract contract = department.getContract(employee);
System.out.println(String.format(" %s. %s, %s. Salary: EUR %d", contract.getPositionName(), employee.getFirstName(), employee.getLastName(), contract.getSalary()));
}
}
System.out.println();
}
}
The fact that it worked is not the cool thing though; the cool thing is that only the hiring or firing department is authorized to send youAreHired and youAreFired messages to the person that is being hired or fired; in a similar way, only a resigning employee can send the iResign message to its department, and only to that department; any other illegitimate message sent from main would trigger an assertion. In a real program you would use exceptions instead of assertions.
Is all of this overkill? This example is admittedly a little extreme. But I feel like this is the essence of OOP. Objects must cooperate to achieve a certain goal i.e. changing the global state of the application according to predetermined pieces of business logic, in this case hiring, firing and resign. Some programmers think that business problems are not suited for OOP, but I disagree; business problems are basically workflows, and they are very simple tasks by themselves, but they involve a lot of actors (i.e. objects), which communicate through messages. Inheritance, polymorphism, and all the patterns are welcome extensions, but they are not the base of the object-oriented process. In particular, reference-based associations are often preferred to implementation inheritance.
Note that by using static analysis, design-by-contract and automatic theorem provers, you would be able to verify that your program is correct, for any possible input, without running it. OOP is the abstraction framework that enables you to think this way. It is not necessarily more compact than procedural programming, and it does not automatically lead to code reuse. But I insist that it is easier to read, modify and extend; let's have a look at this method:
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
resign();
mDepartment = department;
}
The business logic relevant to the use case is the assignment at the end; the if statement is an extension, a special case that only occurs when the person is already an employee in another department. The first three assertions describe forbidden special cases. If one day we want to forbid this automatic resign from the previous department we only need to modify this method:
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment == null);
assert(department.isBeingHired(this));
mDepartment = department;
}
We can also extend the application by making youAreHired a boolean function, which returns true only if the old department is ok with the new hiring. Obviously we may need to change something else, in my case I made Person.resign a boolean function, which in turn may require Department.iResign to be a boolean function:
public boolean youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
if (!resign())
return false;
mDepartment = department;
return true;
}
Now the current employeer has the final word in determining whether an employee can be transferred to another department. The current department could delegate the responsibility of determining this to a Strategy which may in turn take into consideration the projects in which the employee is involved, their deadlines and various contractual constraints.
In essence, adding an order to a customer really is part of business logic. If a bidirectional association is required, and reflection is not an option, and none of the solutions proposed on this and the linked question are satisfactory, I think the only solution is something like this.
first, unless you plan on moving orders between customers, I think you shouldn't provide a setCustomer() method, the customer should be a parameter for the constructor and leave it unchanged.
then, the constructor shouldn't be accessible for the user, only use the factory method of Owner.
There is no single answer. It really depends on the classes involved. In your case, you obviously don't want to give people the option of doing something invalid so I would get rid of Order.SetCustomer.
That may not always be the case though. Like I said, it depends on the classes involved.
If you are maintaining the bidirectional relationship in Customer.placeOrder(Order), why don't you do the same thing in Order.setCustomer(Customer)?
class Order {
private Customer customer;
public void setCustomer (Customer c) {
customer = c;
c.getOrders().add(this);
// ... or Customer.placeOrder(this)
}
}
It seems like duplicating code but it solves the problem. The simpler thing to do though is to avoid bidirectional relationships where possible.
I think the best way in this case is to delegate the responsibility for wiring to another class:
class OrderManager {
void placeOrder(Customer c, Order o){
c.addOrder(o);
o.setCustomer(c);
}
}
class Customer {
private Set<Order> orders = new LinkedHashSet<Order>();
void addOrder(Order o){ orders.add(o); }
}
class Order {
private Customer customer;
void setCustomer(Customer c){ this.customer=c; }
}