Problem
I am thinking about how an inventory could be designed. The requirements for this inventory will be the following:
- There will be predefined item types in the inventory.
- The user can define new item types and add them to the inventory.
- In the interaction with the GUI the user will be shown the item types contained in the inventory and he will click a “+” or a “-” to increase/decrease the quantity of that item.
The initial design I have come up with is the following:
Item.java
public class Item {
private String name;
private String itemId;
private int quantity;
public Item(String name, String itemId) {
this.name=name;
this.itemId=itemId;
this.quantity=0;
}
public void add() {
this.quantity++;
}
public void remove() {
this.quantity--;
}
public String getName() {
return this.name;
}
public String getItemId() {
return this.itemId;
}
public int getQuantity() {
return this.quantity;
}
public String toString() {
String s="";
s+=" name = "+this.name;
s+=" , id = "+this.itemId;
s+=" , quantity = "+this.quantity;
return s;
}
}
and Inventory.java :
public class Inventory {
private ArrayList<Item> items = new ArrayList<Item>();
public Inventory() {
this.items.add(new Item("Book", "4877326352"));
this.items.add(new Item("Pen", "21366363636"));
}
public void increaseQuantity(String itemName) {
for (Item item : this.items) {
if (itemName.equals(item.getName())) {
item.add();
return;
}
}
}
public void decreaseQuantity(String itemName) {
for (Item item : this.items) {
if (itemName.equals(item.getName())) {
if (item.getQuantity()>=0) {
item.remove();
}
return;
}
}
}
public void createItem(String name, String itemId) {
this.items.add(new Item(name,itemId));
}
public String toString() {
String s="";
s+="Inventory contains:n";
for (Item item:this.items) {
s+='t'+item.toString();
}
return s;
}
public void printInventory() {
System.out.println(this.toString());
}
public static void main(String[] args) {
Inventory inventory = new Inventory();
inventory.printInventory();
inventory.increaseQuantity("Book");
inventory.increaseQuantity("Pen");
inventory.printInventory();
inventory.decreaseQuantity("Book");
inventory.printInventory();
inventory.createItem("Pencil", "92827234534");
inventory.printInventory();
inventory.increaseQuantity("Pencil");
inventory.printInventory();
}
}
Now of course there are some issues with this implementation. (e.g there are no checks for creating duplicate item types etc…), yet these issues can be solved easily.
But the thing that worries me the most is the fact that Item has quantity as a field. Is that considered bad design?
If quantity was not a field in item then I guess Inventory would have an ArrayList of items, and increaseQuantity()
would invoke items.add(new Item())
. But then, isn’t it pointless to have duplicate items in an ArrayList when all you need to know is what kind of items you have and in what quantity?
Solution
Yes, having a quantity field in Item
is bad design.
The reason is that it is the wrong abstraction. If you pick up and hold ten pebbles in your hand, the number ten is a property of your hand (because it is how many things it is holding), not the pebble which is just a pebble.
Consider if you drop all the pebbles, now the quantity of pebbles in your hand changes to 0. But if the quantity was a property of the pebble, and you dropped all the pebbles how would you model that would each of the pebbles have a quantity of 0 now?
What if you hand the pebbles over to some one else? Then you would change the quantity in respective hand, but if the quantity was part of the pebble you couldn’t model this transaction at all.
Similarly the quantity should be a property of the inventory (how many of X does it contain), not of the Item
which is just an item.
Somehow this makes me think of Database Normal Forms.
Simply have a Map
with Item
as key and an Integer
quantity as value. This solves your duplicate items problem as well.
Map<Item, Integer> inv = new HasMap<>();
// add x of item ( works for new items too )
inv.put(item, inv.getOrDefault(item, 0) + x);
Note that you will need to implement equals
and hashCode
for Item
.