user1955934
user1955934

Reputation: 3495

Java Object Fields Value Depend on Other Fields - Best Practice Patterns?

I have a simple java object

 public class Order {
  private int quantity;
  private long price;
  private long totalPrice;
 }

I will only be storing quantity and price, and totalPrice field will be generated based on quantity * price.

Now i have method called populateTotalPrice() in Order class. But it seems that i am putting a logic inside an entity class which may be an anti pattern?

My other option, is to use a helper static method.

What is really the best practice for this type of behaviour?

Upvotes: 2

Views: 1305

Answers (3)

Ted Hopp
Ted Hopp

Reputation: 234795

Having a totalPrice field in your entity, where the value is a function of the values of other fields, is very closely related to the idea of denormalization of a database. (From some of the comments you have made to other answers, I gather that you are using this entity with a backing data base table that you want to query.) In particular, it violates 3NF: column values should depend only on key column values. Although storing calculated values violates 3NF, there are sometimes very good performance reasons to do this. As with databases, there are a variety of approaches for dealing with this type of requirement.

You can perhaps move the problem to the database and eliminate the totalPrice field from your Java object. One possibility, depending on the DBMS you are using, is to define your database schema to have a computed column. (Computed columns are not standards SQL, but several systems--such as Microsoft's SQL Server--supports them.) Another possibility is to define a database view (a SELECT statement that is stored in the data base and queried as if it is another table). The view could be something like:

CREATE OR REPLACE VIEW orders_view AS
SELECT quantity, price, quantity * price AS total_price
FROM orders

Your code could then query orders_view instead of orders when it needed to use totalPrice (or total_price).

Finally, you can just denormalize your entity as you are doing and accept the consequences, the primary one being update anomalies: you update price and/or quantity but fail to update the totalPrice field. You can reduce this risk by updating totalPrice in the setters for quantity and price (rather than having a separate populateTotalPrice() method):

public class Order {
    private int quantity;
    private long price;
    private long totalPrice;

    public int getQuantity() { return quantity; }

    public void setQuantity(int newQuantity) {
        quantity = newQuantity;
        updateTotalPrice();
    }

    public long getPrice() { return price; }

    public void setPrice(long newPrice) {
        price = newPrice;
        updateTotalPrice();
    }

    private void updateTotalPrice() {
        totalPrice = quantity * price;
    }

    public long getTotalPrice() { return totalPrice; }
}

Note the absence of a setter for totalPrice. Arranging your code this way ensures that you can't run into a problem by leaving out a call to populateTotalPrice(). (Of course you can still end up with update anomalies if you can change the database values without going through your Java object.)

Some frameworks where you can do these calculations every time an entity is loaded from the table. (For instance, Hibernate has postLoad and with Android Room, you can use LiveData fields.) Then you don't need to store the field in the table at all.

Some further reading on this issue:

Upvotes: 0

The Java practice is to treat an object in terms of properties, not fields. Most properties are based on a backing field, but in your case it makes sense for the property totalPrice to be a calculated property:

public long getTotalPrice() {
  return price * quantity;
}

Upvotes: 4

user1587368
user1587368

Reputation: 316

Yes, you don't have to put the total price in the order to create an invoice.

The total price is calculated during the process of creating an invoice.

Upvotes: 2

Related Questions