Say that the design of my application is such that there are two classes: Person and Company. Also suppose I have defined a UML diagram that defines a one-to-many relationship between Person and Company: every Person object must belong to exactly one Company, and a Company can contain many Persons.
What are some best practices for ensuring that this simple constraint always holds, i.e., that there is never a point in time where a Person object is contained in more than one Company? I've thought of three approaches:
Have perfect, bug-free code that would never violate any of my constaints. However, being a realist, I know that this is difficult or impossible, especially as the number of constraints grows.
Implement an ensureCorrectness() method that manually checks each and every constraint. In this example, it would loop through all Persons, and make sure that exactly one Company contained that Person. If not, it would print an error. I would call this method every so often.
Use, e.g., Hibernate to define a database schema and store the data into a database. In the schema, I can define a constraint to match the constrains in my UML diagram. Then, whenever I persists data into the database, Hibernate will check all the constraints and print an error if something's gone wrong.
But I can't help wondering if there is another, cleaner way to do this in Java, that doesn't rely on (1) perfection, (2) manual validation, or (3) a relational database. Is there a library or framework that would allow me to specify annotations in the code similar to:
#OneToMany(Person, Company)
Or perhaps more specifically:
#OneToMany(Person, Company.persons)
assuming the Company class had a List<Person> persons member variable.
And if I wanted to ensure that a person's social security number is unique across all Persons, I could say:
#Unique(Person.SSN)
Does anything like this exist for Java?
The relation between a Company to Person is not difficult. Make e.g. a list with Person elements contained in Company. The one thing you have to ensure manually is that the list does not contain multiple instances of a single Person.
The other way around is more difficult. You have to manually check this (that each list does not contain multiple instances of the same Person). But you can combine it with the previous restriction:
The length of all lists of persons should be equal as the length of all lists with unique persons.
I do not have much knowledge about databases, but I would go for the second option (ensureCorrectNess) to check the manual constriction above.
I'd go for #1, in combination with encapsulation. This way, the amount of code that has to be 100% bug free is very small
public class Company {
private List<Person> persons = new ArrayList<>();
private List<Person> publicPerson = Collections.unmodifiableList(persons);
public List<Person> getPersons { return publicPersons; }
public void addPerson(Person p) {
... ensure p is removed from old company
p.setCompany(this);
persons.add(p);
}
}
public class Person {
private Company company;
/* pkg-private */ setCompany(Company company) {
this.company = company;
}
public Company getCompany() {
return company;
}
}
Careful, this code is not threadsafe!
Notice that hibernate will only check the constraints if you save to the database. Due to caching, inconsistencies may appear.
I would implement it like that in Java:
public class Company {
Set<Person> persons;
...
public void addPerson(Person person) {
if (person.getCompany() != this) { // Avoiding an infinite loop between addPerson() and setCompany()
person.setCompany(this);
persons.add(person);
}
}
public boolean removePerson(Person person) {
return persons.remove(person);
}
...
}
public class Person {
Company company;
public Person(Company company) {
this.company = company;
}
public void setCompany(Company company) {
if (this.company != null) {
this.company.remove(this);
}
this.company = company;
company.addPerson(this);
}
...
}
In code, Person cannot have more than one Company, and Company has a list of Persons. With the Person(Company) constructor, Person has at least one company assigned.
EDIT: To modify the Set (no duplicates), you have to pass through the addPerson() method that call the Person.setCompany() method. This method will remove the Person from previous Company list and add him to the new Company list.
In setCompany(), you have to call to addPerson(), because programmers can assign directly a Person to a Company without calling first to addPerson().
first you can configure all this in the DB very easily by set the col in the db not null and the customer id unique.
you can use triggers before and after to be sure that the data is remove or added to the DB.
second option you can set all the DB on java classes by using Hash Maps to contain the data.
in my opinion the first option is more easy..
Related
For instance, I have two classes: Book and Customer. Customer has a List which contains all the Books it purchased. I can easily look up a Customer's purchase history with this design.
However, if I want to know how many Customers have bought a particular Book, usually I would look up all Customers purchase history and get those who bought this particular Book. This can be a time consuming looking up process. I wonder if it would be a better approach to add a List inside the Book class, and add all the Customers who bought this particular book to this List.
I wonder if my approach would be better/worse in terms of design. This is definitely making Book-Customer strongly coupled, but I am not sure if there is other ways to implement such method.
Ideally, to be pure, neither the book nor the customer should know about each other. I would instead create a third class, Purchase, containing references to the customer and the book, the date ordered, date shipped, price paid, etc.
Then I'd have a Map<Customer, List<Purchase>> and optionally a Map<Book, List<Purchase>>.
Even Customer class having reference to list of books is not that great.
Keep both Customer and Book classes unaware of each other. Instead maintain maps for your quick reference. e.g. -
Map<Customer, List<Book>> customerToBooks;
Map<Book, List<Customer>> bookToCustomers;
And manipulate these maps through assignBook(Customer c, Book b) and returnBook(Customer c, Book b) methods
One thing you can do is check the list inside of the customer's class checking the book purchase history like so:
Customer.java
public class Customer{
public Set<Book> purchases = new HashSet<Book>();
public void purchaseBook(Book b){
purchases.add(b);
}
}
Original class:
public Set<Customer> customers = new HashSet<Customer>();
public Set<Customer> getCustomersFromBook(Book b){
Set<Customer> ret = new HashSet<Customer>();
for(Customer c : customers){
if(c.purchases.contains(b)){
ret.add(c);
}
}
return ret;
}
Or you can do the same sort of thing, but with the customers inside of a Set in the Book class.
The project has 4 classes. A Person, an Employee that extends Person and an Academic that extends Employee.
I also have a Store, which is a user-made alternative to an Array. One of the functions of Store is ‘elementAt()’, which returns to us an object in Store.
The problem I have is that elementAt() always returns as type Person. This is a huge problem because, in my Controller class, before I let the user perform an action only applicable to an Academic I NEED to check whether the user has actually chosen an employee or not.
public Person elementAt(int index)
{
// Returns element at position index
return list[index];
}
There is one big problem; according to the project specification I cannot alter the Person, Employee, Academic or Store class any further. Meaning, I have to determine the type of the Store index somewhere, somehow within my controller class.
I wanted to run this by people with more experience so thank you for having a look.
Instanceof seems to me the only option you have; and I don't think that its evil to use it in this case. But you are right, it is not the nicest thing in thinking in objects ;o)
At least you might encapsulate that like
public boolean isAcademic(Person p) {
return p instanceof Academic;
}
to concentrate the "code smell" in one position, and make it easier to later refactor it.
I don't know if i got it right, but if you just want to check the returned object type, do this:
Person person = store.elementAt(0);
if (person instanceof Academic) {
//do stuff
}
In the model layer of an application I'm working on, I have an Organization class, that has a one-to-many relationship with a Person class. Person objects can have a number of different roles, based on their one-to-many relationships to another set of objects of the superclass Certificate. To determine if a Person is a "signatory", I call
public boolean isSignatory() {
return this.certificatesAsSignatory.size() > 0;
}
I want to return a list of signatories for an organization, so I'm going to loop through the set of related persons, checking for signatories. What I'd like to do is cache the result, so I don't have to regenerate the data from the database each time. I've added a private field to Organization that looks like
private List<Person> signatories;
and the basic method looks like this
public List<Person> getSignatories() {
for ( final Person person : this.people ) {
if ( person.isSignatory() ) {
this.signatories.add( person );
}
}
return this.signatories;
}
Now, when I call the method to return the list, I'll store the result in signatories and return it. When it's called again, I can check if signatories already contains a list, and return that instead of doing the calculations again.
My question is this: how do I keep the cache of the list of signatories up to date?
So the list contains all persons who are signatories. It would seem a good idea to update that list every time Person changes from being a signatory to not being one, or vice versa. Im guessing you have some method that sets if a Person is a signatory or not? In that function you could make a call to clear the cache so it would refill the list next time it is needed. Im also guessing it can be done when a new Person is inserted into the db and should be a signatory.
Its hard to be more specific since I dont know how your code is sturctured. But the idea of a cache is to reset it when the data thats in it changes.
I've written a java based web application, simple for now since I'm a beginner in this space. What it does is looks up the phone number of a person, when the user enters the name of the person in the jsp page. I'm using a hashmap for now where I've created two objects the person and the number and basically the map is the association of the person to the number. The reason I have person as an object is later on I plan to add more information to the person object. I also plan to eventually move the association to the database. However, in this specific situation where I have a hash map how do I handle the use case of a "person with the same name" can be two different users because according to my hashmap the key is the person object. Specifically, the user can look up the person by name. I also thought of adding a system generated id to the person object to make it unique but it doesn't solve the use case of two people having the same name as when the user is querying for the phone number he will only enter the person's name.
The simplest solution would be to have your value type be a list of people, so:
Map<String, List<Person>> map = new HashMap...
It sounds like your design could do with a bit of work though. While you're prototyping (pre database), for example, is there any reason you need to use a HashMap? Why not just store a List<Person>, and iterate the list each time you want to search? That would let you easily search on other properties of a person too.
Edit: In response to Phoenix's comment.
The approach is to store a list of all people with the given name in lists within the map.
To add a new person, you need to check if a person already exists with their name, and create an empty list to put them into if there isn't already a person. [Sorry, I don't have a compiler handy, so haven't compiled or tested this, but the idea should be right]
void add(Map<String, List<Person>> map, Person p) {
if (!map.containsKey(p.name()) {
map.put(p.name(), new ArrayList<Person>());
}
// The map will always have a (possibly empty) list of people with a given name now
map.get(p.name()).add(p);
}
Looking people up is easy. To print all the people with a given name:
void printPeople(BufferedWriter out, Map<String, List<Person>> map, String name) {
for (Person p : map.get(name)) {
out.println(p.toString());
}
}
What about this?
Map<String, List<Person>> map = new HashMap<String, List<Person>>();
if(!map.contains(personName)){
map.put(personName, new ArrayList<Person>());
}
// Construct Person person = new Person(personName, phoneNumber);
map.get(personName).add(person);
You keep a list of person as Martin suggested and put the values as list of person instead of single person.
While iterating...
for(Person person : map.get(personName)){
// Process person.getPhoneNumber();
}
I'm adding a second answer here. My other answer shows how to implement it with a Map, but I don't think it's worth the effort.
If you're using a HashMap because you're worried about performance, then you'll fix that once you put the database backend in that you've mentioned. As a general rule, don't spend effort optimising code you know you're going to throw away anyway, or don't know for sure even needs optimising.
My solution (pending the real backend), would be to just use a List. You don't need to worry about getting your hashCode algorithm right, and I doubt it's going to come out significantly slower unless you have many thousands of entries.
public class People {
private List<Person> people = new ArrayList<Person>();
public void add(Person p) {
people.add(p);
}
public List<Person> findByName(String name) {
List<Person> result = new ArrayList<Person>();
for (Person p : people) {
if (p.getName().equals(name)) {
result.add(p);
}
}
return result;
}
It's just so much simpler and clearer than the Map solution.
Take my domain class for example
public class Person
{
private Integer id;
private String name;
private String address;
private String telephone;
//Accessors here..
}
This is great for storing 1 instance of a given Person, however, the name for example would most likely change over time, and I would like to retain any previous values, I may wish to see what addresses this person has lived at over the past 10 years.
What are my options for doing this? This is a Java web app so I could potentially have an AUDIT_LOG table on my schema, but that doesn't sound a very reliable way of keeping track of these changes
Another thought is to have a PersonFamily and keep all instances of person, assuming the last item in the List is the most recent, such as..
public class PersonFamily
{
private Integer id;
private List<Person> persons;
//Accessors here...
}
Any suggestions on how I can achieve this? Is there a really clean and simple process I've missed?
Thanks
public class Person
{
private Integer id;
private String name;
private Address address;
}
public class Address {
Integer id;
String line1;
String line2.
}
Then model this in your database either as :
Person Table
id
name
Address Table
id
line1
line2
PersonAddressHistory Table with fields:
id
personId
addressId
activeDate
the last table maintains a list of the current and previous addresses associated with a person, with the current Address being the last entry (i.e. with max value of id).
An option you might consider would be a simple version number tied to class:
public class Person
{
private Integer id;
private Integer version;
private String name;
private String address;
private String telephone;
//additional class stuff...
}
Using this approach, whenever the name, address, or other attributes are updated, the version number is incremented by one. This preserves the original data under the previous version, and allows for easy retrieval of all previous version by id, which does not change.
Google for temporal patterns or event sourcing.
http://martinfowler.com/eaaDev/timeNarrative.html
There are lots of ways to do it, The simplest would be to have a "Person" which has a list of "PersonHistory" objects. Whenever you call a setter, create a new PersonHistory object with the same values as the most recent. Then alter the changed field, and save that in your list.
The problem with that is you would have a lot of redundant data, one for each change. If this is going to be backed by A database, though rather then storing a huge list, you could dump each old instance to the DB whenever a change is made (so you only store the most recent one in memory)
Otherwise, you could have one list for each variable, and store a Tuple with value and the 'step'. So each time a variable is changed, you update a counter, and store that counter with the value that changed.
I think it depends on your usage requirements for the historical data.
For example, with your person example, I would have a "Current / Past" field in the database. For most uses, I would just get the record that is "Current", and it would act as it does now - no changes to DAO or Object model (except perhaps to add start/end timestamps).
When you do require the history, it is likely for very specific reasons, and you can at that time get a separate List ordered by change date. This would be separate to the commonly used data model.
When someone changes their name, clone the Person, change the new record to "Previous", then change the existing record's name, then commit both changes in the same transaction.
Note that if historical data is used very commonly, then the above isn't relevant and you should have a List with first entry being current. This might be the case with address history, which is very commonly used in financial applications. In addition for name changes, the most common change is getting married/divorced, so you should have an extra field - maiden name - in your data model.