因此,我正在研究我的代码,并尝试将抽象工厂设计模式应用于其中。这是情况。
我有一个父类CheckList
和一个子类ShoppingList
。除此之外,我还有ShoppingListItem
类,它是从ListItem
类扩展的。
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));
}
}
我在这里的问题是
ShoppingList.java:9: error: incompatible types: ArrayList<ShoppingListItem> cannot be converted to ArrayList<ListItem> this.items = new ArrayList<ShoppingListItem>();
看起来Java不允许ArrayList<parent>
和ArrayList<child>
之间进行这种继承。我想知道是否有解决方案?我试图使ShoppingList
仅具有ArrayList<ShoppingListItem>
,并且还继承了所有的add / delete / etc方法。这可能吗?
更新
这是根据Konstantin Pozhidaev的答案进行修改后的代码。 (我将在发现后尽快进行压缩)。
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;
}
}
但是,我的代码破坏了我所有的旧JUnit案例。这是我的示例测试之一:
@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());
}
错误输出:
> java.lang.AssertionError: the first item suppose to be Apple
> expected:<Apple> but was:<null>
我认为问题仍然在我的继承人中,但我找不到答案。如果您有任何想法请告诉我。
答案 0 :(得分:0)
您应该在抽象类上使用ArrayList<? extends ListItem>
而不是ArrayList<ListItem>
。
也可以使用equals
方法进行字符串比较。
更新
您的抽象类应类似于:
abstract class CheckList<T extends ListItem> {
ArrayList<T> items;
ArrayList<T> getItems() { return this.items; }
...
实施
public class ShoppingList extends CheckList<ShoppingListItem> {
您应该确定要使用严格的类的通用类。
完整列表:
import java.util.ArrayList;
abstract class CheckList<T extends ListItem> {
String name;
ArrayList<T> items;
String getName() { return this.name; }
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(true);
return true; // target found
}
}
return false; // cannot find the target
}
}
class ListItem {
private String name;
private Boolean completed;
public String getName() {
return name;
}
public Boolean getCompleted() {
return completed;
}
public void setName(String name) {
this.name = name;
}
public void setCompleted(Boolean completed) {
this.completed = completed;
}
}
class ShoppingListItem extends ListItem {
public ShoppingListItem(String name) {
this.setName(name);
}
}
public class ShoppingList extends CheckList<ShoppingListItem> {
public ShoppingList (String name) {
this.name = name;
this.items = new ArrayList<>();
}
public void addItem(String name) {
// add a new ShoppingListItem to items
final ShoppingListItem item = new ShoppingListItem(name);
this.items.add(item);
}
}
答案 1 :(得分:0)
GenericClass<Parent>
和GenericClass<Child>
之间没有继承,但是通配符可以解决您的情况:
ArrayList<? extends ListItem> items = new ArrayList<>(); //list with wildcard
您将可以将扩展ListItem
的内容放入其中。
还可以考虑使用foreach循环甚至更好的lambda表达式使循环更紧凑。例如,您的删除方法:
public boolean deleteItem(String name) {
boolean removed = false;
items.removeIf(item -> {
item.getName().equals(name);
removed = true;
});
return removed;
}
您应该使用equals
方法比较字符串。