Java спасылкі канчатковую зменную перад тым, як быў ініцыялізаваны

У мяне ёсць гэты суперкласса Creature і яго падклас монстар . Цяпер у мяне ёсць гэтая праблема канчатковай зменнай на якую спасылаецца без яго ініцыялізацыі.

public class Creature {

    private int protection;

    public Creature(int protection) {
        setProtection(protection);
    }

    public void setProtection(int p) {
        if(!canHaveAsProtection(p))
            throw new Exception();
        this.protection = p;
    }

    public boolean canHaveAsProtection(int p) {
        return p>0;
    }
}

і падклас:

public class Monster extends Creature {

    private final int maxProtection;

    public Monster(int protection) {
        super(protection);
        this.maxProtection = protection;
    }

    @Override
    public boolean canHaveAsProtection(int p) {
        return p>0 && p

Як вы можаце бачыць, калі я ініцыялізаваць новы монстар , ён будзе выклікаць канструктар Creature з супер (абарона) . У канструктар Істота , метад canHaveAsProtection (р) называецца, які па дынамічнае звязванне прымае перазапісаны адзін у монстар . Аднак гэтая перапішуцца версія выкарыстоўвае апошнюю зменную maxProtection , які не быў ініцыялізаваны яшчэ ... Як я магу вырашыць гэтую праблему?

3
У прыкладзе коды монстар ня падкласы істоты.
дададзена аўтар Ziyao Wei, крыніца
Гэты код не мае ніякага сэнсу. Вы не патрабуеце, што тут?
дададзена аўтар Keppil, крыніца
Так, але maxProtection будзе усталяваны ў становішча Абарона пасля гэтага, так што логіка, як я апісваю, але з двума крокамі замоўлена.
дададзена аўтар Keppil, крыніца
паспрабуйце, калі (! this.canHaveAsProtection (р))
дададзена аўтар Anthony Raimondo, крыніца
Я проста дадаў яго :)
дададзена аўтар Confituur, крыніца
Не, вы патрабуюць дадзенай абароны ў канструктару Монстры менш maxProtection, які яшчэ павінен быць усталяваны.
дададзена аўтар Confituur, крыніца

7 адказы

Некаторыя моманты:

  • only Monster cares about a max value, so only it should know about this concept
  • all Creatures must have a protection > 0
  • don't defer range checking to a separate method
  • the upper and lower bound checking doesn't need to be in the same place
  • use the Decorator Pattern to solve the problem

Звядучы усё гэта разам, ваш код павінен выглядаць наступным чынам:

public class Creature {

    private int protection;

    protected Creature() {
    }

    public Creature(int protection) {
        setProtection(protection);
    }

    public void setProtection(int p) {
        if (p < 0)
            throw new IllegalArgumentException();
        this.protection = p;
    }
}

public class Monster extends Creature {

    private final int maxProtection;

    private Monster(int protection) {
        this.maxProtection = protection;
        setProtection(protection);
    }

    @Override
    public void setProtection(int p) {
        if (protection > maxProtection)
            throw new IllegalArgumentException();
        super.setProtection(p);;
    }

    public static Monster create(int protection) {
        Monster monster = new Monster(protection);
        monster.validate();
        return monster;
    }
}

Вы не паказалі, што праверкі() метад памірае, але калі гэта неабходна толькі для праверкі абароны, я б выдаліць яго і статычны фабрычны метад і зрабіць канструктар Монстраў грамадскасці.

1
дададзена

Monster does not extend Creature in the code you posted.

Калі гэта адбудзецца, я не бачу прычын для монстар , каб атрымаць канчатковую зменную. <�Код> Істота павінен мець канчатковую зменную, і монстар павінен проста атрымаць доступ да яго. Калі павінна быць не больш за валідацыю значэння для абароны, то мне здаецца, што ўвесь Істота асобнікі павінны мець.

Push it up from the Monster to Creature and you're fine. You should have two arguments in the Creature constructor: protection and maxProtection. Throw an IllegalArgumentException if maxProtection < 0 or protection falls outside the range 0..maxProtection.

0
дададзена
Я думаю, што гэта павінна быць засунуць да супер класа і зрабіў частку свайго кантракту.
дададзена аўтар duffymo, крыніца
Я не згодзен - я думаю, што гэта карысным для іх. Мне здаецца, каб быць часткай кантракта для ўстаноўкі ўзроўню абароны, які павінен быць верны для ўсіх істот. Я не згодны з вашым мысленнем і дызайнам.
дададзена аўтар duffymo, крыніца
Гэта ўсяго толькі невялікая частка ўсяго кода, які з'яўляецца больш складаным. Сутнасць заключаецца ў тым: няма ніякіх падставаў для зменнай maxProtection быць у падклас. Але калі гэта адзінае рашэнне ...
дададзена аўтар Confituur, крыніца
Усе астатнія падкласы Істоты таксама маюць зменную maxProtection тое, што не мае сэнсу для іх. Гэта правільны шлях?
дададзена аўтар Confituur, крыніца

Гэта звязана з вашай ініцыялізацыі ланцуга.

Даччыны клас павінен быць цалкам я ініцыялізаваны перад бацькам можа быць адфарматаваны.

У цяперашні час, гэта выглядае наступным чынам ...

Monster->Creature->Creature#setProtection->Monster#canHaveAsProtection ...

дзе maxProtextion ня адфарматаваны, таму што Істота constrcutor не вярнулася.

Рашэнне было б адкласці ініцыялізацыю, як некаторыя, магчыма, у метадзе ініцыялізацыі, што канструктары могуць патэлефанаваць

0
дададзена

Па прычынах, названым у іншых адказах, зрабіце наступнае:

public Creature(int protection) {
    this.protection = protection;
}

public Monster(int protection) {
    super(protection + 1);
    this.maxProtection = protection;
}

That correction + 1 seems to be your intended logic because of the < maxProtection.

0
дададзена

Гэта сапраўды дрэнная практыка, каб выклікаць публічныя метады ў канструктару, асабліва, калі вы чакаеце яго падкласа.

Ваш клас павінен быць цвёрдым і ініцыялізаваць яго стан самастойна. Я думаю, вы павінны ўсталяваць Абарона пераменная відавочна ў канструктару:

public Creature(int protection) {
    this.protection = protection;
}

Калі вы сапраўды хочаце праверыць свае параметры ў канструктару, то атрымаць агульныя функцыянальныя магчымасці для прыватных метадаў:

public Creature(int protection) {
    Assert.isTrue(isProtectionValid(p));
    this.protection = protection;
}

private static boolean isProtectionValid(int p) {
    return p > 0;
}

public boolean canHaveAsProtection(int p) {
    return isProtectionValid(p);
}
0
дададзена

Вы не павінны выклікаць публічныя метады ў канструктару. Замест таго, каб вы маглі змяніць мадыфікатар канструктара да абароненым/прыватнаму і выкарыстоўваць фабрычныя метады, у якіх называецца праверка:

public class Creature {
    private int protection;

    protected Creature(int protection) {
        this.protection = protection;
    }

    public void setProtection(int protection) {
        if (!canHaveAsProtection(protection))
            throw new IllegalArgumentException();
        this.protection = protection;
    }

    public boolean canHaveAsProtection(int protection) {
        return protection > 0;
    }

    protected void validate() {
        if (!canHaveAsProtection(this.protection))
            throw new IllegalArgumentException();
    }

    public static Creature create(int protection) {
        Creature creature = new Creature(protection);
        creature.validate();
        return creature;
    }
}

І монстар :

public class Monster extends Creature {

    private final int maxProtection;

    private Monster(int protection) {
        super(protection);
        this.maxProtection = protection;
    }

    @Override
    public boolean canHaveAsProtection(int p) {
       //I changed '<' to '<=' because '<' wouldn't work anyway
        return p > 0 && p <= maxProtection;
    }

    public static Monster create(int protection) {
        Monster monster = new Monster(protection);
        monster.validate();
        return monster;
    }
}
0
дададзена

Як наконт таго, каб адмяніць абарону усталяванай ваннай ўсталяваць макс першай ваннай, чым выклік на супер абароны набору.

    @override
   public void setProtection(int p) {
        this.maxProtection = p;
    super.setProtection(p);
    }
0
дададзена
Вы спрабавалі гэта адзін і зрабіў гэта працуе для вас? Я проста цікава!
дададзена аўтар docDevil, крыніца