I was given 2 classes for the assignment: Sale and DiscountSale (which extends Sale). I'm supposed to create a new class called MultiItemSale which will create an array (shopping cart) of both Sale and DiscountSale objects. But I can't get methods from DiscountSale to work on DiscountSale ojbects within the array.
class Sale (the base class) has some methods, setName() and setPrice() in particular.
class DiscountSale extends Sale, so it can use setName() and setPrice(), but it also has setDiscount() among other things.
in MultiItemSale:
Sale[] shoppingCart = new Sale[numOfItems];
From my understanding, since DiscountSale extends Sale, both Sale and Discount Sale objects should be able to placed within this array, correct?
I use a for loop to ask if an item is discounted. If it isn't then:
shoppingCart[i] = new Sale();
if it is discounted:
shoppingCart[i] = new DiscountSale();
And this is where I begin to run into issues:
The following works, because setName() and setPrice() are from the Sale class
Also, this is all under an if-statement that says if item is discounted, then:
shoppingCart[i] = new DiscountSale();
shoppingCart[i].setName(name);
shoppingCart[i].setPrice(price);
But if I try to do this I get errors because setDiscount() is from DiscountSale:
shoppingCart[i].setDiscount(discount);
Eclipse tells me, "The method setDiscount(double) is undefined for the type Sale". If
shoppingCart[i] = new DiscountSale();
why can't I use a method from DiscountSale on that object? I think I have a misunderstanding of how polymorphism and arrays work.
All the compiler knows is that you have Sales, so those are the only methods you can use. Polymorphism is for the situation when you have the same function calls on different kinds of objects and the same function call will behave differently depending on what kind of object it is.
In this example, name, price, and discount could be parameters of your constructor. That way you could pass them when you say new, and you wouldn't have to call a setting method afterwards.
Edit: Looking at the Wikipedia article on the Circle-Ellipse Problem, it occurs to me that any Sale has an implicit discount of 0%. You could use only DiscountSales and be able to access all their members, perhaps including a flag indicating whether the discount can be changed.
In the parlance of object-oriented design, a DiscountSale is a Sale.
Normally, a program would collect Sale and DiscoutSale objects into the same Sale collection in order to perform common Sale processing on those objects in the collection defined by the Sale API. So it doesn't make a lot of sense that you would try to use a statement like:
Sale[] shoppingCart = new Sale[] { ... };
:
:
shoppingCart[i].setDiscount(...);
Because a Sale isn't a DiscountSale, setting a discount rate on a top level Sale item, as you've designed it, isn't part of its API and the statement doesn't make a lot of sense.
DiscountSale objects will inherit the methods from Sale (a DiscountSale is a Sale), but Sale objects will have no knowledge of any subclass-specific methods defined in DiscountSale (a Sale object doesn't have to be a DiscountSale).
So what to do?
A common solution to a problem like this is to take advantage of polymorphism. For example, in your Sale class make a method such as getNetPrice() part of its API.
public class Sale {
protected double price;
:
:
public double getPrice() { return price; } // return original price
public double getNetPrice() { return price; } // return discounted price
:
:
}
Notice that the two methods in Sale are identical. How come? Because their contracts are different. The first returns the original price. The second is specified to return the discounted price. Because Sale objects have no discount, it simply returns the original price as well.
However, the DiscountSale class would take advantage of polymorphism to fulfill the API contract:
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));
}
:
:
}
Here, DiscountSale objects are defined so that the discount rate is set at the time the object is created. This is pretty straightforward since, as we've said, setting a discount rate on Sale objects in the collection (which may or may not be discounted) is more confusing.
The DiscountSale uses the Sale contract and overrides the getNetPrice() method to calculate and return the discounted price. In this way, both objects can be in the same collection and share a common API to get at the nondiscounted or discounted prices.
Related
I am really pretty new to java and have a homework assignment due in a couple days. Unfortunately when my teacher try's to help me out I just still don't understand it. I need to create two classes to compute a discounted loan and then a main class to call them all and actually make it work. This is my first class its all correct based on what the teacher wants.
package Project2;
public class Loan {
public double money;
public double interest;
public double loanperiod;
public double totaldiscount;
public Loan(){
money=0;
interest=0;
loanperiod=0;
}
//set money,interest,and loanperiod
public void setmoney(double newmoney){
money=newmoney;
}
public void setinterest(double newinterest){
interest=newinterest;
}
public void setloanperiod(double newloanperiod){
loanperiod=newloanperiod;
}
//get money,interest,and loanperiod
public double getmoney(){
return money;
}
public double getinterest(){
return interest;
}
public double getloanperiod(){
return loanperiod;
}
public double gettotaldiscount(){
return totaldiscount;
}
}
The second class I need to create another object. Then I have to create a method to compute the discounted loan and a method to describe the program, a method to get userinputs and a method calling the correct method from from the loan class above to display the output.
So far this is what I have for the second class, just a description method. But I am really confused as to how I am going to make a method to compute the discountedloan (I have the formula), and how to create a method to get userinputs. If I could get any help at all I would appreciate it. But please explain I really want to learn this rather then copy.
package Project2;
public class DiscountedLoan {
public DiscountedLoan(){
}
public void description(){
System.out.println("This program computes the proceeds of a discounted loan. Loan amount is in dollars and cents, Annual interest rate is in percentage, and the loan period is in number of years.");
}
}
There are a couple of object oriented principles you need to understand. The first is the idea of what a class is. A class is a thing. You have the definition, or the actual code, that represents the 'design' of the thing. It does stuff (methods) and has state (variables). An instance of a class is an actual implementation.
You can apply this principle to the real world easliy. For example, a car has a design somewhere. Engineers create models, CAD drawings etc and that is comparable to the coded class. At some point that design is turned into an actual car that is comparable to an instance of a class when your program runs.
In your code you have created a class definition for loan. It is just the design for what a loan looks like but doesn't actually contain any loan data. So when your program runs you need to create an instance of that loan to represent an actual loan. You can then use the methods of that class to populate the details, i.e. money, interest, etc.
When writing a method you need to decide a couple of things. What data does my method need to do its work and what data will it give back to me. In this case you may want to write a method that takes in a loan and returns a number to represent the discount. Your other method really just needs to display the user interface and call the appropriate methods with the right data.
This will allow you to read in integers that a user enters.
public int getLoanFromUserInput(){
try{
Scanner reader = new Scanner(System.in);
System.out.println("Enter a loan balance: ");
int n = reader.nextInt();
}catch(TypeMismatchException e){
System.out.println("Please enter a valid integer");
}
}
I have a accountclass which has an arraylist that holds objects from two other classes. These classes are Deposit/Checks which are extended from a generic transaction class.
parent class:
Transaction(Double Amount,Int transactionType,Int transactionNumber)
//amount holds amount to be edited in the balance
//type =1,2,3;check,deposit,or fee
//number=number transaction in the account done.
check extends transaction;
super(constructor)
deposit extends transaction
super(constructor);
Except that check has a variable, checknumber and deposit has two variables, check/cash which == amount to be edited.
When program is done,and prints summary I need to have these objects print their variables.
Before I had a simple arraylist.get(i).getID, if ID == (the number I want)
print=arralist.get(i).getAmount(i), that was before they were separated classes,now that they are, separated i cant call each object, but how do i individually ask for that objects variable in the arraylist.
I cant do arraylist.getobject.getcash arraylist.getobject.getcheck
because that 'geter' is in the deposit class, not in the account class,and those members are private so i cant simply add them to the accountclass where the arraylist sits.
So pretty much,
how to print member variables from objects which are in arraylist, that have different unique variables.
The instanceof operator is what you're looking for. It will let you find out which class the element in the ArrayList belongs to, and then you can take the appropriate actions. Here's an example:
if(ArrayList.get(i) instanceof Check) {
// take actions specific to checks
String checkNum = ArrayList.get(i).getCheckNumber();
}
if(ArrayList.get(i) instanceof Deposit){
//take actions specific to deposits
double cash = ArrayList.get(i).getCash();
}
etc...
I'm working on a Java project where I have a superclass called Personnel, and two subclasses; Manager and Worker.
The subclasses contain separate variables that are used to hold information about their pay, and I previously had method getSalary() for Manager and getWage() for Worker. However, I wanted a number of these to be accessible through a for-loop so I put an abstract method into the Personnel class called getAnnualIncome() and put a corresponding method into both subclasses:
public abstract class Personnel
{
//attributes of each instance of class
protected String name;
protected int payrollNum;
protected String dept;
//abstract method to be defined in subclasses
public abstract float getAnnualIncome();
}
In Manager:
public float getAnnualIncome()
{
//convert salary variable to real number
float salaryAsFloat = salary;
//return real number
return salaryAsFloat;
}
In Worker:
public float getAnnualIncome()
{
//number of weeks in a year as constant value
final int weeksInYear = 52;
//weekly wage by number of weeks in a year
return ((hourlyRate * hoursPerWeek) * weeksInYear);
}
This all works fine in theory, but when I came to actually implementing the for-loop I mentioned (using an array of the Personnel class with objects from both subclasses as elements), the following piece of code did not recognize the getAnnualIncome() method (this is taken from the executable main class):
for (int index = 0; index < employee.length; ++index)
{
System.out.printf(employee[index].getName()
+ "\t\t" + "£%.2f %n", employee[index].getAnnualIncome());
//error message appears here ^^ 'method is undefined in 'Personnel'
}
Not really sure what's going wrong here, thought I'd covered everything that needed to be done. As you can see from my code extracts, the method is in the superclass!
I don't really know where to go from here, any shove in the right direction would be greatly appreciated!
Thanks,
Mark
Are you able to create an array of the Personnel class with objects from both subclasses as elements?
because that itself will give you error. "Can not convert subclass(Worker/ Manager) to Personnel[].
In case that works fine for you, than the problem is with the annotation #Override.
When you made an abstract class method, you are telling the JVM, "Childs" from this "Parent" WILL have those methods, and will either perform them, or have their "Childs" perform them.
Absctract class methods cannot use Objects details in themselfs, they are not able to be instantiated.
Either have getAnnualIncome() in both Worker and Manager (and their "Children") or have that abstract class do the method.
To fix your issue, use the annotation #Override, to inform Java 6+ that the code is legitimated (while optional, this could help), and check that the hierarchy is correct
Does this Java code involving a Book class use proper encapsulation? I feel it can be a lot simpler if I omit some methods but we're required to every method that is in there [especially setters and getters].
Here's the first class:
public class Book
{
private String title;
private double price;
private final double SALES_TAX=0.075;
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title=title;
}
public double getPrice()
{
return price;
}
public void setPrice(double price)
{
this.price=price;
}
public double getSalesTax()
{
return SALES_TAX;
}
public double increasePrice(double incresePrice)
{
return incresePrice;
}
public double calculateSales(double sales)
{
return sales;
}
}
And the second class:
public class BookDriver
{
public static void main(String[] args)
{
Scanner keyboard=new Scanner(System.in);
Book bookOne=new Book();
Book bookTwo=new Book();
bookOne.setTitle("Life of Pi");
System.out.print("Enter number to buy of "+bookOne.getTitle()+": ");
bookOne.setPrice(13.50*bookOne.calculateSales(keyboard.nextDouble()));
bookOne.setPrice((bookOne.getPrice()*bookOne.getSalesTax())+bookOne.getPrice());
System.out.print("Cost for "+bookOne.getTitle()+" $");
System.out.printf("%.2f"+"\n",bookOne.getPrice());
bookTwo.setTitle("Harry Potter: The Goblet Of Fire");
System.out.print("Enter number to buy of "+bookTwo.getTitle()+": ");
bookTwo.setPrice(22.00*bookTwo.calculateSales(keyboard.nextDouble()));
bookTwo.setPrice((bookTwo.getPrice()*bookTwo.getSalesTax())+bookTwo.getPrice());
System.out.print("Cost for "+bookTwo.getTitle()+" $");
System.out.printf("%.2f"+"\n",bookTwo.getPrice());
System.out.print("Enter percent increase of "+bookOne.getTitle()+": ");
bookOne.setPrice((bookOne.getPrice()*bookOne.increasePrice(keyboard.nextDouble()))+bookOne.getPrice());
System.out.printf("Cost of "+bookOne.getTitle()+": $"+"%.2f"+"\n",bookOne.getPrice());
System.out.print("Enter percent increase of "+bookTwo.getTitle()+": ");
bookTwo.setPrice((bookTwo.getPrice()*bookTwo.increasePrice(keyboard.nextDouble()))+bookTwo.getPrice());
System.out.printf("Cost of "+bookTwo.getTitle()+": $"+"%.2f"+"\n",bookTwo.getPrice());
keyboard.close();
}
}
I know that this is a lot so I'm not really expecting much in terms of a response but anything would help. Thanks!!
Let's look at the point of encapsulation. You have a Class which consists of properties and methods. The idea behind encapsulation is, you want the methods in your class to be the only way to change the value (state) of the properties. Think of it like this: if some other code in the program wants to change the value of one of the properties, it cannot do it itself, it must ask a method on the class they reside in to do it. That way, you control access to the properties.
The way this is implemented is with getter and setter methods of which you have created a few. A getter method returns the value of the property and a setter method changes it to a new value.
1.
Your getter and setter methods up to increasePrice() are good. You are preventing access to the properties other than from the methods on your class.
2.
increasePrice() only spits out what was passed into it. It doesn't change the value of any of the properties and thus has no purpose. If you want to be able to increase the price you can change the method like so:
public void increasePrice(double amountOfPriceIncrease) {
price += amountOfPriceIncrease;
/*
price += amountOfPriceIncrease is the same as
price = price + amountOfPriceIncrease
*/
}
3.
This line is a bit troubling. For starters, increasePrice() doesn't do anything other than spit out what was put into it and secondly, there is a lot going on in the one line that makes it complicated and hard to follow.
bookTwo.setPrice((bookTwo.getPrice()*bookTwo.increasePrice(keyboard.nextDouble()))+bookTwo.getPrice());
You dont necessarily need all the setters. For example, its probably reasonable to assume that a book has a title, and it doesnt change. So you can make it final, omit the setter, and pass it into the constructor.
Also, think about how you're modelling things. Is sales tax a property of a book? I'd say not.
Because all the required variables title, price for class Book are set to private, and that access can only be used using get..(), and changing it if possible can only be used using set..(some variable) or an instance method affecting one of the fields, it demonstrates proper encapsulation, so all getting and setting are regulated.
However, I spotted several mistakes in BookDriver, namely with the improper usage of Book fields.
The price should change only through setPrice or increasePrice.
You should also implement getPriceAfterTax to determine after-tax prices for a book.
The total cost of the books you bought should not involve any setPrice.
There is a mistake with public double calculateSales(double sales). It does nothing but returns back sales. The calculateSales should calculate the total cost of the book(s) being bought, using one int variable, and you also resorted in changing the price of these books, which shouldn't happen. It is the reason why you wrote messy code, as in the excerpt
bookTwo.setPrice(22.00*bookTwo.calculateSales(keyboard.nextDouble()));
bookTwo.setPrice((bookTwo.getPrice()*bookTwo.getSalesTax())+bookTwo.getPrice());
This avoids the potential case of changing the values of that BOOK object to unexpected or unusual values and value combinations.
Additionally, SALES_TAX can be made into a public static final double instead, as it is assumed to never change, and you can simply obtain SALE_TAX without requiring getSalesTax().
The last two methods do not make much sense. You simply return what you put in. Do it this way:
public double increasePrice(double increase)
{
price *= increase;
}
public double calculateSales(double sales)
{
//return {your formula}
}
I'm working on homework and I won't post the full code but I'm stuck on something that's probably simple and I can't find it in my book so I need to be pointed in the right direction.
I'm working with classes and interfaces.
Basically in my main code I have a line like this
CheckingAccount checking = new CheckingAccount(1.0); // $1 monthly fee
I was told to create a class called CheckingAccount and in that class I am told "This class should include an instance variable for the monthly fee that's initialized to the value that's passed to the constructor.
Since I'm new this is barely english to me and I'm assuming what that is saying is to take that 1.00 fee and declare it in the CheckingAccount class so I can create a method using that variable to calculate something.
soooo... How do I do that? I know how to create an instance variable it would be something like
public double monthly fee =
but then what? or I could be wrong. I am really doing bad at this java stuff. Any help is appreciated.
I guess another way to ask it is am I just declaring it as 1.0? or am I "importing" that value in case it changes later at some point you don't have to go through the code to change it in all of the classes?
Your requirement (as I read it) is to initialize the instance variable in the constructor, and your instantiation (new CheckingAccount(1.0);) shows you are on the right track.
What your class will need is a constructor method which receives and sets that value 1.0.
// Instance var declaration
private double monthly_fee;
// Constructor receives a double as its only param and sets the member variable
public CheckingAccount(double initial_monthly_fee) {
monthly_fee = inital_monthly_fee;
}
#Jeremy:
You're pretty much spot on (at least, your interpretation of what you've been asked to do matches my interpretation); while I don't know the actual design of the class, or whether monthly_fee needs to be public, in pseudocode you'd be looking at something like:
class CheckingAccount {
//Instance variable
double monthly_fee;
//Constructor
CheckingAccount(double monthly_fee) {
this.monthly_fee = monthly_fee;
}
//Function to multiply instance variable by some multiplier
//Arguments: Value to multiply the monthly fee by
double multiply_fee(double a_multiplier) {
return monthly_fee*a_multiplier;
}
}
You are basically right. If you haven't already, you should create a new class (it should be in it's own file called CheckingAccount) like this:
/** This is the class of Account with monthly fee. */
public class CheckingAccount {
// This is the instance variable.
// It should be 'private' for reasons you will surely learn soon.
// And NOT static, since that would be a class variable, not an instance one.
// The capitalization is called camelCase, google it up. Or, even better, find 'JavaBeans naming conventions'
private double monthlyFee;
// This is the constructor. It is called when you create the account.
// It takes one parameter, the fee, which initializes our instance variable.
// Keyword 'this' means 'this instance, this object'.
public CheckingAccount(double monthlyFee) {
this.monthlyFee = monthlyFee;
}
// Here will be your methods to calculate something...
}
Don't create an instance variable as public. It's bad practice because it violates the principle of information hiding (your teacher may call this abstraction). Instead, you can create an instance variable as
public final class CheckingAccount {
private double monthlyFee;
// The rest of the class goes here
public double getMonthlyFee() { // This method is called an accessor for monthlyFee
return monthlyFee;
}
}
Note that monthly fee isn't a valid variable name because it contains a space, and variable names can't contain spaces. Also notice that other classes access monthlyFee through a method. Because you define the method rather than making the variable public, you control access to monthlyFee a lot better (another class can't just change monthlyFee unless you define a method that makes that change).
Now to accessing monthlyFee. The method getMonthlyFee is called an accessor for a reason: it allows other classes to access that variable. So, those other classes can just call the method to get the monthly fee out of a CheckingAccount:
CheckingAccount checking = new CheckingAccount(1.0);
// A bunch of other code can go here
double fee = checking.getMonthlyFee(); // Now fee is 1.0