【问题标题】:List<parent> List<child> inheritance solution [duplicate]List<parent> List<child> 继承解决方案 [重复]
【发布时间】:2019-07-10 22:46:16
【问题描述】:

所以我正在编写我的代码并尝试将抽象工厂设计模式应用到其中。情况是这样的。

我有一个父类 CheckList 和一个子类 ShoppingList。除此之外,我还有从ListItemclass 扩展而来的ShoppingListItemclass。

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&lt;parent&gt;ArrayList&lt;child&gt; 之间的这种继承。我想知道是否有任何解决方案?我试图让ShoppingList 只有一个ArrayList&lt;ShoppingListItem&gt; 并且还继承了所有的添加/删除/等方法。这可能吗?

更新

这是我根据 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>

我认为问题仍然存在于我的继承中,但我不知道在哪里。如果您有任何想法,请告诉我。

【问题讨论】:

  • 你可以尝试用通配符ArrayList&lt;? extends ListItem&gt; items;定义列表
  • 为什么不直接使用菱形运算符? new ArrayList&lt;&gt;()?
  • @RealSkeptic 你的意思是CheckList?对不起,我不明白大声笑

标签: java list oop inheritance design-patterns


【解决方案1】:

您应该在抽象类上使用ArrayList&lt;? extends ListItem&gt; 而不是ArrayList&lt;ListItem&gt;

同样使用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);
    }
}

【讨论】:

  • 所以我按照你说的做了,它显示错误:找不到合适的方法用于 add(ShoppingListItem) items.add(new ShoppingListItem(name));
  • @ProgrammingDonkey 更新了答案。
【解决方案2】:

GenericClass&lt;Parent&gt;GenericClass&lt;Child&gt; 之间没有继承关系,但是有一个针对您的情况的解决方案,通配符:

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方法比较字符串。

【讨论】:

    猜你喜欢
    • 2010-11-13
    • 2012-11-15
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多