Как я могу создать суперкласс для двух разных подклассов - PullRequest
0 голосов
/ 04 января 2019

Представь что-то вроде этого: У меня есть два класса: NodeA и NodeB. NodeA хранит Integer и имеет метод-получатель. NodeB нет.

Теперь я хочу создать узел суперкласса, который может вызвать метод получения. Однако я не хочу, чтобы NodeB сохранял целое число. Как мне справиться с этим?

С моим кодом ниже, NodeB выбрасывает исключение. У узла суперкласса есть Optinal.

public abstract class Node {
    public Integer getValue();
}

public class NodeA extends Node {

    public Integer value;

    public NodeA() {}

    @Override   
    public Integer getValue() {
        return this.value;
    }
}

public class NodeB extends Node {

    public NodeB() {}

    @Override   
    public Integer getValue() {
        throw new Exception();
    }
}

Редактировать: здесь добавлено объяснение из ложного ответа ниже.

Моя работа заключается в создании карточной игры. У меня есть NormalCards и Jokers. Карты NormalC имеют значение, а шутки - нет. Причина, по которой я хочу суперкласс, заключается в том, что я могу создать список

Представьте, что вы хотите обойти список и суммировать все значения.

Поскольку шутки не имеют значений, я должен проверить, является ли карта джокером. Если нет, приведите его к карточке NormalCard и получите значение. Мой Учитель сказал, что слепки - это зло ... поэтому я ищу альтернативу.

Ответы [ 4 ]

0 голосов
/ 23 января 2019

Решением этой проблемы было не создавать суперклаза. С вами все было в порядке: это был плохой дизайн.

Мы изменили его и создали одну карточку класса с двумя статическими фабричными методами : createJoker () createNormalCard (int value)

Спасибо за все ваши ответы. Вы многому научитесь за несколько недель.

0 голосов
/ 04 января 2019

на базовом уровне, вы не правы в дизайне; вы нарушаете инкапсуляцию. Я называю это LRN2OOP

Вместо того, чтобы перебирать коллекцию карточек и складывать стоимость, Вы должны перебрать коллекцию карточек и сделать так, чтобы каждая карточка добавляла свою ценность в аккумулятор. В частности, клиенту класса Card не нужно знать о внутреннем представлении значения Card (это шаблон Visitor).

Это не лучшее решение, но вот пример кода:

public interface CardScoreBlammy
{
  void addToScore(int cardScore);
}

public interface MyCard
{
   void accumulateScore(ScoreBlammy);

   ... other shared Card functionality.
}

public class CardHolder
implements CardScoreBlammy
{
  private int accumumatedScore = 0;
  private List<MyCard> cardList;
  ... populate the cardList somehow.

  public void addToScore(final int cardScore)
  {
    accumulatedScore += cardScore;
  }

  public int getScoreTotal()
  {
    accumulatedScore = 0;

    for (final MyCard currentCard : cardList)
    {
      currentCard.accumulateScore(this);
    }

    return accumulatedScore;
  }
}


public class NotAJoker
implements MyCard
{
  private int myValue;

  public void accumulateScore(final ScoreBlammy scoreBlammy)
  {
    scoreBlammy.addToScore(myValue)
  }
}

public class IRJoker
implements MyCard
{
  public void accumulateScore(final ScoreBlammy scoreBlammy)
  {
    // do nothing
  }
}
0 голосов
/ 04 января 2019

Я бы определенно переоценил вашу стратегию дизайна здесь, если это возможно. Использовать один класс и просто вернуть 0 для Джокера намного проще, чем то, что вы пытаетесь сделать.

Если, по какой-то причине, это не вариант, то интерфейс будет хорошим вариантом. Создайте интерфейс Card и оба класса реализуют его. Обратите внимание на использование Integer, а не int в типе возвращаемого значения для учета нулевых значений. Кроме того, поскольку вы уже знаете все возможные значения для карты, не являющейся джокером, перечисление хорошо подходит для определения этого:

public interface Card {
    public Integer getValue();
}

public class Joker implements Card {

    @Override
    public Integer getValue() {
        return null;
    }

}

public class NotJoker implements Card {
    private CARD_TYPE cardType;

    public NotJoker(CARD_TYPE type) {
        this.cardType = type;
    }

    public CARD_TYPE getType() {
        return cardType;
    }

    @Override
    public Integer getValue() {
        return cardType.getValue();
    }

}

public enum CARD_TYPE {
    ACE(11), KING(10), QUEEN(10), JACK(10),
    TEN(10), NINE(9), EIGHT(8), SEVEN(7),
    SIX(6), FIVE(5), FOUR(4), THREE(3),
    TWO(2);

    private final int value;

    CARD_TYPE(int value) {
        this.value = value;
    }

    public int getValue() {return value;}
}

Теперь мы можем создать наш класс для хранения карт, Deck. Мы просто используем card.getValue() для всех карт и проверяем, равен ли Integer null, прежде чем добавить его значение:

public class Deck {

    private ArrayList<Card> cardList;

    public Deck() {
        cardList = new ArrayList<Card>();
    }

    public void addCard(Card card) {
        cardList.add(card);
    }

    public int getTotalScore() {
        int totalScore = 0;

        for(Card card : cardList) {
            Integer value = card.getValue();
            if(value != null) {
                totalScore += value;
            }
        }
        return totalScore;
    }
}

А вот быстрый тест, чтобы доказать, что он работает:

public class CardGame {

    public static void main(String[] args) {

        Deck deck = new Deck();

        deck.addCard(new Joker());
        deck.addCard(new NotJoker(CARD_TYPE.FIVE));
        deck.addCard(new NotJoker(CARD_TYPE.FOUR));
        deck.addCard(new NotJoker(CARD_TYPE.ACE));
        deck.addCard(new NotJoker(CARD_TYPE.KING));
        deck.addCard(new Joker());
        deck.addCard(new NotJoker(CARD_TYPE.SEVEN));

        //total score: 37
        System.out.println("total score: " + deck.getTotalScore());
    }

}
0 голосов
/ 04 января 2019

Короткий ответ: Вы не.

Немного более длинный ответ: если вы чувствуете необходимость сделать это, вы должны улучшить свой дизайн. Это нарушает принципы проектирования ОО, особенно LSP .

Просто изображение, имеющее такой метод:

void printValue(Node node) {
   System.out.println(node.getValue());
}

Как вы узнаете, будет ли это работать? Во время выполнения он может выдать исключение, он может работать, кто знает, что явно плохо.

Что вам, скорее всего, нужно - это создать интерфейс

public interface ValueProvider {
   Integer getValue();
}

и реализовать это только для NodeA. Учитывая ваш пример карточной игры, в которой значение может быть необязательным, вы могли бы рассмотреть возможность возврата null в getValue из NodeB. Немного лучше было бы использовать Optional<Integer> в качестве типа возврата для getValue().

Тогда вы можете иметь метод в NodeA, например:

@Override   
public Optional<Integer> getValue() {
    return Optional.of(this.value);
}

и NodeB

@Override   
public Optional<Integer> getValue() {
    return Optional.empty();
}
...