Java 黑箱与继承

Java 黑箱与继承,java,oop,inheritance,Java,Oop,Inheritance,各位好,飞越者 想象一下下面的基类 import java.util.ArrayList; public class Array { private ArrayList<Object> a = new ArrayList<Object>(); public void add(Object element) { a.add(element); } public void addAll(Object elements[]) { f

各位好,飞越者

想象一下下面的基类

import java.util.ArrayList;

public class Array
{
  private ArrayList<Object> a = new ArrayList<Object>();

  public void add(Object element)
  {
    a.add(element);
  }

  public void addAll(Object elements[])
  {
    for (int i = 0; i < elements.length; ++i)
      a.add(elements[i]); // this line is going to be changed
  }
}
Array add()将元素添加到本地ArrayList。 数组addAll()为每个元素调用本地ArrayList add

ArrayCount add()调用其父级的add(),然后递增计数。 ArrayCount addAll()调用其父级的addAll(),然后按元素数递增计数

现在换零钱。基类中注释的代码行更改为以下内容:

  public void addAll(Object elements[])
  {
    for (int i = 0; i < elements.length; ++i)
      add(elements[i]); // this line was changed
  }
public void addAll(对象元素[])
{
对于(int i=0;i
现在ArrayCount addAll()调用其父级的addAll(),后者在内部调用已被派生类重写的add()

派生类的作者必须知道基类是如何实现的。而且他们必须了解基类中的每一个变化,因为它可能以不可预测的方式破坏他们的派生类

我正在寻找一个正确的方法来实现这一点,这将尊重黑箱编程的概念。因为这个示例强制派生类的编写者知道基类是如何实现的,并且知道每个更改

我假设“黑盒”的意思是:“派生类的实现者必须不知道基类数组的实现细节”。我会选择使用委托的装饰师,因为这可能是更好的方法:

public class ArrayCount {
  private int   count = 0;
  private Array a;

  public ArrayCount(Array a) {
    this.a = a;
  }

  public void add(Object element) {
    a.add(element);
    ++count;
  }

  public void addAll(Object elements[]) {
    a.addAll(elements);
    count += elments.length;
  }

}
注意:为了简洁起见,我没有检查输入参数

如果
Array
ArrayCount
都实现了相同的接口,例如
IArray
,则仍然可以互换使用这些类:

interface IArray {
 public void add(Object element);
 public void addAll(Object elements[]);
}
...
Array implements IArray {...}
ArrayCount implements IArray {...}

将基类方法标记为final,但包括用于扩展的支持方法

import java.util.ArrayList;

public class Array {
    private final ArrayList<Object> a = new ArrayList<Object>();

    public final void add(Object element) {
        a.add(element);
        afterAdd(element);
    }

    public final void addAll(Object[] elements) {
        for (Object element : elements) {
            a.add(element);
        }
        afterAddAll(elements);
    }

    protected void afterAddAll(Object[] elements) {
        return;
    }

    protected void afterAdd(Object element) {
        return;
    }
}
当您使用黑盒方法时,您只需调用对象的方法,因此您不关心它是如何实现的

类的公共方法是定义您提供什么和获得什么的契约

维护该类的开发人员可以更改合同或方法签名以外的任何内容

如果您扩展了一个类,并且要重写一个或多个方法,那么您就不应该关心类的实现,因为您要专门化类的某些行为

为了清晰地分离具有相同接口的不同类,您应该使用java接口,这样每个开发人员都可以自己实现业务逻辑

当您知道某个方法可以被专门化时,您可以将一个类设计为可以从其他人扩展

但是,如果您不想这样做,您可以通过定义这些方法final来决定不能重写该方法


通过这种方式,您可以告诉将使用您的代码的其他开发人员,您不希望扩展某些行为。

基类中的更改是通过使调用虚拟化并将实现委托给派生类来显式更改契约。你的问题不清楚。有办法做什么?请澄清你的需要,确实不清楚。我编辑了这个句子
import java.util.ArrayList;

public class Array {
    private final ArrayList<Object> a = new ArrayList<Object>();

    public final void add(Object element) {
        a.add(element);
        afterAdd(element);
    }

    public final void addAll(Object[] elements) {
        for (Object element : elements) {
            a.add(element);
        }
        afterAddAll(elements);
    }

    protected void afterAddAll(Object[] elements) {
        return;
    }

    protected void afterAdd(Object element) {
        return;
    }
}
public class ArrayCount extends Array {
    private int count = 0;

    @Override
    protected void afterAdd(Object element) {
        ++count;
    }

    @Override
    protected void afterAddAll(Object[] elements) {
        count += elements.length;
    }
}