【问题标题】:black box and inheritance黑盒与继承
【发布时间】:2016-08-05 15:44:12
【问题描述】:

你好 Stackoverflowers,

想象一下下面的基类

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
  }
}

这是派生类:

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

  @Override
  public void add(Object element)
  {
    super.add(element);
    ++count;
  }

  @Override
  public void addAll(Object elements[])
  {
    super.addAll(elements);
    count += elements.length;
  }
}

Array add() 将元素添加到本地 ArrayList。 Array addAll() 为每个元素调用本地 ArrayList add。

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

现在进行重大更改。 Base 类中的注释代码行更改为:

  public void addAll(Object elements[])
  {
    for (int i = 0; i < elements.length; ++i)
      add(elements[i]); // this line was changed
  }

现在 ArrayCount addAll() 调用其父级的 addAll() 内部调用已被 Derived 类覆盖的 add()。

Derived 类的作者必须知道 Base 类是如何实现的。并且必须告知他们 Base 类的每一个变化,因为它可能会以不可预知的方式破坏他们的 Derived 类。

我正在寻找一种尊重黑盒编程概念的正确方法来实现这一点。因为这个例子迫使派生类的编写者知道基类是如何实现的,并且知道每一个变化

【问题讨论】:

  • 基类中的更改通过使调用虚拟化并将实现委托给派生类来显式更改合同。您的问题不清楚。
  • 有什么办法吗?请说明您的需求
  • 确实不清楚。我编辑了句子

标签: java oop inheritance


【解决方案1】:

我假设“黑盒”是指:“派生类的实现者一定不知道基类 Array 的实现细节”。我会选择使用委托的装饰器,因为这可能是更好的方法:

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;
  }

}

注意:为简洁起见,我省略了输入参数检查。

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

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

【讨论】:

    【解决方案2】:

    当您使用 黑盒 方法时,您只需调用对象的方法,因此您不必关心它是如何实现的。

    类的公共方法是一个契约,它定义了你提供什么以及你得到什么。

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

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

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

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

    但如果您不希望这样,您可以通过定义那些方法 final 来决定该方法不能被覆盖。

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

    【讨论】:

      【解决方案3】:

      将基类方法标记为最终方法,但包括扩展的支持方法。

      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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-14
        相关资源
        最近更新 更多