使用组合来利用来自 Java 抽象集合 类 的继承是不好的做法吗?

Is using composition to leverage inheritance from Java abstract collections classes bad practice?

很多时候我发现自己(看起来)在从抽象集合 classes 继承时结合了组合和继承,我不禁觉得它是 技术上的 在我做的时候冲突的设计范例。

/** Custom String List implementation */
public class MyStringList extends AbstractList<String>
{
    private final AbstractList<String> _myStringList;

    public MyStringList()
    {
        this._myStringList = new ArrayList<String>();
    }

    public MyStringList(Collection<String> stringCollection)
    {
        if (stringCollection.contains(null))
        {
            throw new NullPointerException("Null values not permitted in MyStringList");
        }
        else
        {
            this._myStringList = new ArrayList<String>(stringCollection);
        }
    }

    @Override
    public String get(int index)
    {
        return this._myStringList.get(index);
    }

    @Override
    public int size()
    {
        return this._myStringList.size();
    }

    @Override
    public String set(int index, String aString)
    {
        ++this.modCount;
        return this._myStringList.set(index, Objects.requireNonNull(aString));
    }

    @Override
    public void add(int index, String aString)
    {
        ++this.modCount;
        this._myStringList.add(index, Objects.requireNonNull(aString));
    }

    @Override
    public boolean add(String aString)
    {
        ++this.modCount;
        return this._myStringList.add(Objects.requireNonNull(aString));
    }

    @Override
    public String remove(int index)
    {
        ++this.modCount;
        return this._myStringList.remove(index);
    }

    // Method to make this list implementation distinct from ArrayList for the sake of
    // this Whosebug question example
    public String[] getNumericContaining()
    {
        return this._myStringList.stream()
                                 .filter(aString -> aString.codePoints().anyMatch(Character::isDigit))
                                 .toArray(String[]::new);
    }

    // Another method to make this list implementation distinct from ArrayList for
    // the sake of this Whosebug question example
    public String[] getUpperCaseContaining()
    {
        return this._myStringList.stream()
                                 .filter(aString -> aString.codePoints().anyMatch(Character::isUpperCase))
                                 .toArray(String[]::new);
    }
}

这种将内部抽象集合对象作为 class 对象继承自(继承)的支持对象(组合)的设计是否被认为是利用各种抽象集合的“正确”方式classes 在 java.util 包中定义?

你在不必要地组合事物。如果您想拥有示例中的内容,请遵循 Lino 的建议:

public class MyStringList extends ArrayList<String> {

    public String[] getNumericContaining() {
        return this.stream()
                   .filter(aString -> aString.codePoints().anyMatch(Character::isDigit))
                   .toArray(String[]::new);
    }

    public String[] getUpperCaseContaining() {
        return this.stream()
                   .filter(aString -> aString.codePoints().anyMatch(Character::isUpperCase))
                   .toArray(String[]::new);
    }
}

无论多少次,常规 List<String> 都是您所需要的,因为您可以将额外的行为提取到封装列表的 class,例如

public class MySomeService {
    
    // This could be passed in, loaded from somewhere, etc.
    private List<String> foo;

    public void serviceMethod() {
        doSomething();
        String[] numbers = getNumericContaining();
        doSomethingElse(numbers);
    }

    // The previous methods
    private String[] getNumericContaining() {
        foo.stream(). // and so on
}

这取决于您的列表本身是否确实是一个 class,或者它是否只是您在某个时候需要的特殊口味。如果它是第一个,它可能应该得到它自己的 class,如果是后者,它就没有。

最后,尽管 OOP 告诉您将数据和行为放在同一个地方,但有时将它们放在不同的地方是有意义的,因此可以使用方法或函数。只需将列表作为参数传递,它将适用于所有 Collection classes 而不仅仅是你的特殊列表。