So I am working on my code and trying to apply abstract factory design pattern into it. Here's the situation.
I have a parent class CheckList
and a child class ShoppingList
. Aside from this, I also have ShoppingListItem
class which extended from ListItem
class.
public abstract class CheckList {
String name;
ArrayList<ListItem> items;
public String getName() { return this.name; };
public ArrayList<ListItem> getItems() { return this.items; };
public String setName(String name) { return this.name = name; };
public abstract void addItem(String name);
public boolean editItem(String oldName, String newName) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName() == oldName) {
items.get(i).setName(newName);
return true; // target found
}
}
return false; // cannot find the target
}
public boolean deleteItem(String name) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName() == name) {
items.remove(i);
return true; // target found
}
}
return false; // cannot find the target
}
public boolean completeItem(String name) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName() == name) {
items.get(i).setCompleted();
return true; // target found
}
}
return false; // cannot find the target
}
}
public class ShoppingList extends CheckList {
public ShoppingList (String name) {
this.name = name;
this.items = new ArrayList<ShoppingListItem>();
}
public void addItem(String name) {
// add a new ShoppingListItem to items
items.add(new ShoppingListItem(name));
}
}
The issue I have here is that
ShoppingList.java:9: error: incompatible types: ArrayList<ShoppingListItem> cannot be converted to ArrayList<ListItem> this.items = new ArrayList<ShoppingListItem>();
Looks like that Java does not allow this kind of inheritance between ArrayList<parent>
and ArrayList<child>
. I am wondering if there any solution for this? I am trying to make ShoppingList
only has a ArrayList<ShoppingListItem>
and also inherited all the add/delete/etc methods. Is this possible?
UPDATE
Here's my code after revising based on Konstantin Pozhidaev's answer. (I will be working on compacting it soon after I figure this out).
import java.util.ArrayList;
// CheckList.java
public abstract class CheckList <T extends ListItem> {
String name;
ArrayList<T> items;
public String getName() { return this.name; };
public ArrayList<T> getItems() { return this.items; };
public String setName(String name) { return this.name = name; };
public abstract void addItem(String name);
public boolean editItem(String oldName, String newName) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName().equals(oldName)) {
items.get(i).setName(newName);
return true; // target found
}
}
return false; // cannot find the target
}
public boolean deleteItem(String name) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName().equals(name)) {
items.remove(i);
return true; // target found
}
}
return false; // cannot find the target
}
public boolean completeItem(String name) {
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).getName().equals(name)) {
items.get(i).setCompleted();
return true; // target found
}
}
return false; // cannot find the target
}
}
// ShoppingList.java
public class ShoppingList extends CheckList<ShoppingListItem> {
public ShoppingList (String name) {
this.name = name;
this.items = new ArrayList<ShoppingListItem>();
}
public void addItem(String name) {
// add a new ShoppingListItem to items
items.add(new ShoppingListItem(name));
}
}
// ListItem.java
public abstract class ListItem {
String name;
boolean completed;
public String getName() { return this.name; }
public boolean getStatus() { return this.completed; }
public void setName(String newName) { this.name = newName; }
public void setCompleted() { this.completed = true; }
}
// ShoppingListItem.java
public class ShoppingListItem extends ListItem {
private String name;
private boolean completed;
public ShoppingListItem(String name) {
System.out.println(name);
this.name = name;
System.out.println(this.name);
this.completed = false;
}
}
However, my code broke all my old JUnit cases. Here's one of my sample tests:
@Test public void testShoppingListAddItem() {
User userUnderTest = new User("Shen");
// groceries list items
userUnderTest.createShoppingList("Groceries");
ShoppingList groceries = userUnderTest.getShoppingList().get(0);
groceries.addItem("Apple");
groceries.addItem("Banana");
ArrayList<ShoppingListItem> groceriesItems = groceries.getItems();
// house renovations list items
userUnderTest.createShoppingList("House Renovation");
ShoppingList hr = userUnderTest.getShoppingList().get(1);
hr.addItem("Paint");
hr.addItem("Flooring");
ArrayList<ShoppingListItem> hrItems = hr.getItems();
// assertions
assertEquals("the first item suppose to be Apple",
"Apple", groceriesItems.get(0).getName());
assertEquals("the second item suppose to be Banana",
"Banana", groceriesItems.get(1).getName());
assertEquals("the first item suppose to be Paint",
"Paint", hrItems.get(0).getName());
assertEquals("the second iten suppose to be Flooring",
"Flooring", hrItems.get(1).getName());
}
Error output:
> java.lang.AssertionError: the first item suppose to be Apple
> expected:<Apple> but was:<null>
I think the issue is still in my inheritance but I cannot find out where. Please let me know if you have any idea.