【问题标题】:Java abstract parent calling child method before child is initialized in parent constructor在父构造函数中初始化子之前的Java抽象父调用子方法
【发布时间】:2016-04-28 18:05:22
【问题描述】:

我有以下课程:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public Parent ()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

class Child extends Parent
{
    private String DBSelection;
    private String[] DBSelectionArgs;

    public Child (String selection, String... selectionArgs)
    {
        super();
        this.DBSelection = selection;
        this.DBSelectionArgs = selectionArgs;
    }

    @Override
    public int size()
    {
        //FAILS because Parent calls size before DBSelectionArgs is initialized
        String temp = "";
        for(String str : DBSelectionArgs)
           temp += str;
        return temp.length;

        //This function basically does a calculation that should not be
        //done before hand. I have posted the exact method below.
    }
}

class ClassDependentOnSize 
{
    public ClassDependentOnSize(int size)
    {

    }
}

虽然这不是我的 exact 类,但这是同样的问题。我写了这个来删除所有不必要的代码。

如你所见,超类试图在子类完成初始化之前调用size()来构造依赖于size的类。我很好奇过去有人如何解决这个问题。我相信每个人都知道, super() 必须是子构造函数的第一行。正如我已经列出了这些课程,这是一个糟糕的设计吗?感觉这个问题应该是以前发生过的,但是找不到解决办法。

编辑: 这是确切的方法。它用于 Android 应用程序。

protected Cursor getCursor()
{
    if (songCursor == null)
    {
        songCursor = GET_SONGS_CURSOR(getContext(), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString(), selection, selectionArgs, selection);

        if (!songCursor.moveToFirst())
            Standard.Loge("|NewPlaylist.getCursor| Could not move to first.");
    }

    int count = songCursor.getCount();
    songCursor.close();
    return count;
}

【问题讨论】:

标签: java inheritance constructor abstract


【解决方案1】:

我以前肯定遇到过这个问题。经验教训是,您永远不应该在 Parent 构造函数中调用非私有方法,这样就不会发生这种情况

【讨论】:

  • 除非它们是最终的
  • 从技术上讲,父母正在调用在孩子中实现的抽象方法,但我明白你在说什么。有共同的解决办法吗?
  • @AndrewNo 在构造对象后调用的方法调用中,您需要做的工作是您试图做的事情。这可能会使对象最初处于无效状态,因此如果在正确初始化之前使用它,则应抛出异常
  • @ControlAltDel 这实际上是我要问的。我只是这样做了,它可以工作,但这感觉像是一个糟糕的设计,但我不知道该怎么做。我会按照你刚才建议的方式保留它,但你对这个设计有什么看法?
  • @AndrewNo 很明显,这是一个杂牌。问题是:这将涉及程序的多少部分?有多少人将使用/修改此代码?否则,您可以创建一个工厂来创建您的对象,这样您就可以在其他人使用它们之前对其进行初始化......有时,您只需要接受妥协
【解决方案2】:

针对您的特定情况的简单解决方案是将大小作为参数传递给父构造函数。

这当然假设你真正的问题具有相同的特征,即基类构造函数所需的所有信息在调用构造函数时都可用。

【讨论】:

  • 是的,但原始发帖人说这不是他/她的确切问题
  • ControlAltDel 是正确的,我无法事先确定大小,因为它是在 size 方法中计算的。我可以更新我的问题,但代码会变得更复杂。
【解决方案3】:

更改父级以将大小作为参数是一种选择:

public Parent (int size)
{
    this.classDependentOnSize = new ClassDependentOnSize(size);
}

...

public Child (String selection, String... selectionArgs)
{
    super(selectionArgs.length);
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
}

另一种选择,有点像黑客,是有一个 init 方法,必须在构造后调用:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public final void init()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

...

public Child (String selection, String... selectionArgs)
{
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
    init();
}

这里的正确答案可能会改变你的代码结构,但是,如果没有更具体的细节,我无法就你想如何去做这件事提供有意义的反馈。

【讨论】:

  • 我会更新我的问题以更好地反映问题。真正的代码太复杂了,我不想用无用的信息压倒任何人,但我做了短暂的改变。
  • 不幸的是孩子必须计算尺寸。在child初始化之前我无法确定大小,这是一个问题,因为先初始化了parent。
  • 至于你的第二个选项,这就是我正在做的,但你是对的,它确实感觉像一个黑客哈哈。
猜你喜欢
  • 2021-12-21
  • 2011-03-06
  • 2013-02-28
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多