2015-09-13 2 views
2

Мне дали 2 класса для задания: Sale and DiscountSale (который распространяется на продажу). Я должен создать новый класс MultiItemSale, который создаст массив (корзину покупок) объектов Sale и DiscountSale. Но я не могу получить методы от DiscountSale для работы с функциями DiscountSale внутри массива.Методы устранения неполадок на объектах полиморфного массива в Java

Класс Продажа (базовый класс) имеет некоторые методы, setName() и setPrice() в частности.

класс DiscountSale расширяет продажу, поэтому он может использовать setName() и setPrice(), но также имеет setDiscount() между прочим.

в MultiItemSale:

Sale[] shoppingCart = new Sale[numOfItems]; 

Из моего понимания, так как DiscountSale распространяется Продажа, как продажа и объекты Продажи Скидки должна быть в состоянии в пределах этого массива, правильно?

Я использую цикл for, чтобы узнать, снижен ли предмет. Если это не так, то:

shoppingCart[i] = new Sale(); 

, если она со скидкой:

shoppingCart[i] = new DiscountSale(); 

И это, когда я начинаю работать в вопросах:

следующие работы, потому что SetName() и setPrice() из класса Продажи

Кроме того, это все под оператором if, который говорит, что если товар дисконтирован, то:

shoppingCart[i] = new DiscountSale(); 
shoppingCart[i].setName(name); 
shoppingCart[i].setPrice(price); 

Но если я пытаюсь сделать это, я получаю ошибки, потому что setDiscount() от DiscountSale:

shoppingCart[i].setDiscount(discount); 

Eclipse, говорит мне, «Метод setDiscount (дважды) не определено для типа продажи». Если

shoppingCart[i] = new DiscountSale(); 

Почему я не могу использовать метод DiscountSale для этого объекта? Я думаю, что я неправильно понимаю, как работают полиморфизм и массивы.

+0

Возможный дубликат http://stackoverflow.com/questions/2559854/accessing-subclass-members-from-a-superclass-pointer-c – cxw

ответ

2

Все компиляторы знают, что у вас есть Sale, так что это единственные методы, которые вы можете использовать. Полиморфизм относится к ситуации, когда у вас есть функции, вызывающие разные объекты, и один и тот же вызов функции будет вести себя по-разному в зависимости от того, какой именно объект он есть.

В этом примере имя, цена и скидка могут быть параметрами вашего конструктора. Таким образом, вы можете передать их, когда вы скажете new, и вам не придется впоследствии вызывать метод настройки.

Редактировать: Глядя на the Wikipedia article on the Circle-Ellipse Problem, это происходит со мной, что любой Sale имеет неявную скидку в размере 0%. Вы можете использовать только DiscountSale и иметь доступ ко всем своим членам, возможно, включая флаг, указывающий, можно ли изменить скидку.

+0

Спасибо за ответ. Я тоже думал об этом, и это хорошее решение, но единственная проблема заключается в том, что позже в проекте я должен сделать так, чтобы пользователь мог вернуться и отредактировать некоторые детали отдельных элементов в своей тележке. Так скажите, что пользователь поставил скидку на 20%, мне нужно сделать так, чтобы они могли сказать, что на самом деле это всего лишь 15%, и было бы просто просто запустить «shoppingCart [i] .setDiscount (newDiscount) '. Полагаю, я мог бы просто создать новый объект, если бы они когда-либо хотели редактировать детали определенного элемента. –

1

В языке объектно-ориентированный дизайн, DiscountSaleявляетсяSale.

Обычно, программа будет собирать Sale и DiscoutSale объектов в том же Sale коллекции для того, чтобы выполнить общую Sale обработки этих объектов в набор, определенный API Sale. Так что это не делает много смысла, что вы бы попытаться использовать такое заявление:

Sale[] shoppingCart = new Sale[] { ... }; 
    : 
    : 
shoppingCart[i].setDiscount(...); 

Sale Поскольку не DiscountSale, установив учетную ставку на верхнем уровне Sale пункт, как вы» ve спроектировал его, не является частью его API, и утверждение не имеет большого смысла.

DiscountSale объекты наследуют методы из SaleDiscountSaleявляетсяSale), но Sale объекты не будут иметь знание любых методов подкласса конкретных, определенных в DiscountSaleSale объект не должен быть DiscountSale).

Итак, что делать?

Общим решением такой проблемы является использование полиморфизма. Например, в вашем классе Sale сделайте такой способ, как getNetPrice(), часть его API.

public class Sale { 

    protected double price; 
    : 
    : 
    public double getPrice() { return price; } // return original price 

    public double getNetPrice() { return price; } // return discounted price 
    : 
    : 
} 

Обратите внимание, что эти два метода в Sale идентичны. Как так? Потому что их контрактов различны. Первый возвращает первоначальную цену. Вторая указана для возврата дисконтированной цены. Поскольку объекты Sale не имеют никакой скидки, он просто возвращает первоначальную цену.

Однако DiscountSale класса воспользуется полиморфизмом для выполнения контракта API:

public class DiscountSale extends Sale { 

    private double discountRate; // specified as percent off (0.0 to 1.0) 
    : 
    : 

    @Override 
    public double getNetPrice() { 
     return (super.price - (super.price * discountRate)); 
    } 
    : 
    : 
} 

Здесь DiscountSale объектов определены так, что учетная ставка устанавливается в момент создания объекта. Это довольно просто, поскольку, как мы уже говорили, установление ставки дисконтирования на Sale объектах в коллекции (которые могут быть или не могут быть дисконтированы) более сбивает с толку.

DiscountSale использует договор Sale и переопределяет метод getNetPrice() для расчета и возврата уцененной стоимости. Таким образом, оба объекта могут находиться в одной коллекции и совместно использовать общий API для получения недисконтированных или дисконтированных цен.

+0

Спасибо за это.Я хотел сделать свой класс MultiItemSale без изменения чего-либо в классах Sale и DiscountSale, но вопрос никогда не говорил, что я не мог редактировать два заданных класса, так что, возможно, это была бы хорошая идея. –

Смежные вопросы