使用组合来利用来自 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 而不仅仅是你的特殊列表。
很多时候我发现自己(看起来)在从抽象集合 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 而不仅仅是你的特殊列表。