Java methods and classes - java

I'm having a bit of trouble with one of my assignments given to me by my professor. Here is the prompt:
Modify the Customer class to include changeStreetO, changeCityO, changeStateO, and changeZipO methods. Modify the Account class to include a changeAddressO method that has street, city, state, and zip parameters. Modify the Bank application to test the changeAddressO method.
I have the changeStreetO, changeCityO, and changeStateO, and changeZipO. However, I'm confused on the section in bold with the ChangeAddressO method. I think I understand how to write the parameters, but I'm unsure of what is supposed to go within the actual method, and how it fits in with the rest of the program. Here is my current code.
import java.text.NumberFormat;
import java.io.*;
import java.util.*;
public class BankModification
{
public class Account
{
private double balance;
private Customer cust;
public Account(double bal, String fName, String lName, String str, String city, String st, String zip)
{
balance = bal;
cust = new Customer(fName, lName, str, city, st, zip);
/**
* Returns the current balance
* pre: none
* post: The account balance has been returned
*/
}
public double getBalance()
{
return (balance);
}
/**
* A deposit is made to the account
* pre: none
* post: The balance has been increased by the amount of the deposit.
*/
public void deposit(double amt)
{
balance += amt;
/**
* A withdrawal is made from the account if there is enough money
* pre: none
* post: The balance has been decreased by the amount withdrawn.
*/
}
public void withdrawal(double amt)
{
if (amt <= balance)
balance -= amt;
else
System. out. println ("Not enough money in account.");
}
/**
* Returns a String that represents the Account object.
* pre: none
* post: A string representing the Account object has been returned.
*/
public String toString()
{
String accountString;
NumberFormat money = NumberFormat.getCurrencyInstance();
accountString = cust.toString();
accountString += "Current balance is " + money.format (balance);
return (accountString) ;
}
public changeAddressO(String street, String city, String state, zip_)
{
}
public class Customer
{
private String firstName, lastName, street, city,state, zip_;
/**
* constructor
* pre: none
* post: A Customer object has been created.
* Customer data has been initialized with parameters
*/
public Customer(String fName, String lName, String str,
String c, String s, String z)
{
firstName = fName;
lastName = lName;
street = str;
city = c;
state = s;
zip_ = z;
}
/**
* Returns a String that represents the Customer Object
* pre: none
* post: A string representing the Account object has been returned.
*/
public String toString()
{
String custString;
custString=firstName + " " + lastName + "\n";
custString +=street + "\n";
custString += city + ", "+state+ " " + zip_ + "\n";
return(custString);
}
public void ChangeStreetO(String newStreet)
{
street = newStreet;
}
public void ChangeCityO(String newCity)
{
city = newCity;
}
public void ChangeStateO(String newState)
{
state = newState;
}
public void ChangeZipO(String newZip)
{
zip_ = newZip;
}
}
}
}
I'm not sure if I'm missing something essential, but without the changeAddressO method, the program compiles. I'm simply unable to figure out what I need to put in the changeAddressO since I made methods with the chageStreetO, changeCityO, changeStateO, and changeZipO. I'm still having a bit of difficulty with classes and methods. Could someone provide some insight/guidance to help figure out this problem? Thank you for your time.

You just need to change the address of the customer:
public void changeAddressO(String street, String city, String state, String zip)
{
cust.changeAddress(street);
cust.changeCity(city);
cust.changeState(state);
cust.changeZip(zip);
}

public void changeAddressO(String street, String city, String state, String zip_)
{
this.street = street;
this.city = city;
this. state = state;
this.zip_ = zip_;
}
And you are probably going to want to put it inside of your Customer class since you made the street, city, state, and zip private.

First of all, change this
public changeAddressO(String street, String city, String state, zip_)
{
}
to
public void changeAddressO(String street, String city, String state, String zip_)
{
}
All functions need a return type, and all parameters need a type before the name. This function's return type is void meaning it returns nothing to the calling function. Change it to String or int or something else as necessary.
At the very least, now your code will compile.
In addition, all of the nested classes are very confusing. Your professor didn't give it to you this way I hope.
Start by changing this:
public class BankModification
{
public class Account
{
//Lots of stuff
public class Customer
{
//Lots of stuff
}
}
}
to this (eliminating all publics except the first):
public class BankModification
{
}
class Account
{
//Lots of stuff
}
class Customer
{
//Lots of stuff
}
This doesn't change anything functionally, but at least it's less confusing (notice there's nothing in BankModification which isn't very helpful.)
"Modify the Bank application to test the changeAddressO method."
What bank application? I would expect to see a
public static final void main(String[] as_cmdLineParams)
somewhere in there. This is the function that actually executes when you type java BankModification on the command line (since BankModification is the public class, only its main will be executed).
Some random observations to at least get you thinking.

Related

Java - subclass and superclass relationship

I'm working on a homework assignment for my Java course and I'm completely lost. I guess I don't fully understand subclass and superclass relationships, but I'm trying my best to trudge along. The assignment asks us to do this:
The class Stock.java represents purchased shares of a given stock. You want to create a type of object for stocks which pay dividends.
The amount of dividends that each shareholder receives is proportional to the number of shares that person owns. Not every stock pays dividends, so you wouldn't want to add this functionality directly to the Stock class. Instead, you should create a new class called DividendStock that extends Stock and adds this new behavior.
Each DividendStock object will inherit the symbol, total shares, and total cost from the Stock superclass. You will need to add a field to record the amount of the dividends paid.
The dividend payments that are recorded should be considered to be profit for the stockholder. The overall profit of a DividendStock is equal to the profit from the stock's price plus any dividends. This amount is computed as the market value (number of shares times current price) minus the total cost paid for the shares, plus the amount of dividends paid.
Here is the stock.java file
/**
* A Stock object represents purchases of shares of a
* company's stock.
*
*/
public class Stock {
private String symbol;
private int totalShares;
private double totalCost;
/**
* Initializes a new Stock with no shares purchased
* #param symbol = the symbol for the trading shares
*/
public Stock(String symbol) {
this.symbol = symbol;
totalShares = 0;
totalCost = 0.0;
}
/**
* Returns the total profit or loss earned on this stock
* #param currentPrice = the price of the share on the stock exchange
* #return
*/
public double getProfit(double currentPrice) {
double marketValue = totalShares * currentPrice;
return marketValue - totalCost;
}
/**
* Record purchase of the given shares at the given price
* #param shares = the number of shares purchased
* #param pricePerShare = the price paid for each share of stock
*/
public void purchase(int shares, double pricePerShare) {
totalShares += shares;
totalCost += shares * pricePerShare;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public int getTotalShares() {
return totalShares;
}
public void setTotalShares(int totalShares) {
this.totalShares = totalShares;
}
public double getTotalCost() {
return totalCost;
}
public void setTotalCost(double totalCost) {
this.totalCost = totalCost;
}
}
I have started working on a subclass called DividendStock.java, but I'm not sure what I'm missing and what I need to do to actually test if its working or not. Does anyone have any tips?
public class DividendStock extends Stock{
private double dividends;
private double profit;
public DividendStock(String symbol){
super(symbol);
dividends = 0.0;
profit = 0.0;
}
public double payDividend(double amountPerShare){
dividends += amountPerShare*getTotalShares();
return dividends;
}
public double profit(double amountPerShare) {
profit = super.getProfit(profit) + payDividend(amountPerShare);
return profit;
}
}
One tip, keep it simple if you don't understand it, that way you learn it best. Here a working example for you.
class MySuperClass {
protected String whoami;
MySuperClass() {
this.whoami = "I'm the Superclass";
}
void whoAmI() {
System.out.println(whoami);
}
}
class MySubClass extends MySuperClass {
MySubClass() {
super.whoami = "I'm the Subclass";
}
}
public class TestWorld {
public static void main(String[] args) {
MySuperClass bigbro = new MySuperClass();
MySubClass littlesis = new MySubClass();
bigbro.whoAmI();
littlesis.whoAmI();
}
}

Can anyone help me with "tostring" method in java?

Im doing an OOP assignment.. It has four classes Person, student and employee both extends person and instructor that extends employee. .
I have done Almost everything i could but i cant print out values using tostring method and Cant fill the array.I have used getter setter and all the constructor and methods are there still cant get any output. heres the person class and all the remain three classes have been made. plus the main file
abstract class Person
{
protected int Id;//"protected"Only child can use this
protected String Name;
public Person() {}
public Person(int id,String name)
{
this.Id=id;
this.Name=name;
}
public int getId()
{
return this.Id;
}
public void setId(int id)
{
this.Id=id;
}
public String getName()
{
return Name;
}
public void setName(String name)
{
this.Name=name;
}
public String toString()
{
return Id + Name + " is a student ";
}
public static int getMaxID()
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////
public class Employee extends Person
{
protected double Salary;
protected String employeeName;
public Employee() {}
public Employee(double salary)
{
this.Salary=salary;
}
public Employee(String employeename)
{
this.employeeName=employeename;
}
public String getemployeeName()
{
return employeeName;
}
public void setemployeeName(String employeename)
{
this.employeeName=employeename;
}
public double getSalary()
{
return this.Salary;
}
public void setSalary(double salary)
{
this.Salary=salary;
}
public String toString()
{
return employeeName + " is an instructor earning a salary of " + Salary;
}
}
////////////////////////////////////////////////////////////////////////////////
public class Student extends Person
{
protected int teacherID;
protected String teacherName;
protected String studentName;
public Student() {}
public Student(int teacherid,String teachername)
{
this.teacherID=teacherid;
this.teacherName=teachername;
}
public Student(String studentname)
{
this.studentName=studentname;
}
public Student(String teachername, String studentname, Person[] person_array)
{
this.teacherName=teachername;
this.studentName=studentname;
}
public int getteacherID()
{
return this.teacherID;
}
public void setteacherID(int teacherid)
{
this.teacherID=teacherid;
}
public String getteacherName()
{
return teacherName;
}
public void setteacherName(String teachername)
{
this.teacherName=teachername;
}
public String toString()
{
return studentName + " is a student ";
}
}
////////////////////////////////////////////////////////////////////////////////
public class Instructor extends Employee
{
int[] studentID=new int[10];
protected String instructorName;
public Instructor(String instructorname)
{
this.instructorName=instructorname;
}
public Instructor(String instructorname, double salary)
{
this.instructorName=instructorname;
this.Salary=salary;
}
public double getSalary()
{
return Salary;
}
public void setSalary(int salary)
{
this.Salary=salary;
}
public String getinstructorName()
{
return instructorName;
}
public void setinstructorName(String instructorname)
{
this.instructorName=instructorname;
}
static void findStudents(Person[] person_array)
{
}
public String toString()
{
return instructorName + " is an instructor earning a salary of " + Salary;
}
}
////////////////////////////////////////////////////////////////////////////////
//CIS 459.23 Lab 2
//Due Oct 30 (Sunday)
//OSU wants you write some classes for their Personnel Record System. To make it simple,
//consider only 4 classes: Person, Employee, Instructor and Student. The following figure
//illustrates the relationship between these 4 classes. The Person class is the parent class of the
//Employee class and the Student class. The Employee class is the parent class of the Instructor
//class.
//The following are the tasks you need to complete for each of these classes.
// Create appropriate fields for each class. Necessary fields are listed. Add your own fields if
//needed. Some fields need to have appropriate constraint. Use your own way to make sure
//that these constraints are satisfied.
//o Person
//ID: int, starting from 1 and should be unique
//Name: String
//o Employee
//Salary: double and should not be negative
//o Student (For simplicity, assume that a student has at most 1 teacher)
//TeacherID: int. It’s his/her instructor's ID. 0 if no instructor is given
//TeacherName: String
//o Instructor:
// StudentIDArray: int array. An array of students’ IDs of this instructor. Set the
// array size to be 10, initially all 0s, assuming an instructor won’t have more than
// 10 students.
// All the above fields are private and only accessible through the access methods.
// A “toString()” method for each class to print out all the available information about the
// current object. In Person class “toString()” is declared as abstract.
// A static “findStudents(Person[] personArray)” method in the Instructor class to fill an
// instructor object’s students ID array, and the corresponding students’ TeacherID fields. See
// the test program for better understanding.
// Person should be declared as abstract class.
// Provide multiple constructors/methods if needed. Check the test.java program to see what
// constructors/methods are necessary and what actions they should do.
// If a class can use the parent class method and constructor, use “super” to call it to reduce the
// redundant code.
// Make sure this test.java program can work with your class.
// sample output. From this sample output, you’ll know what information you should print out
// for a specific object.
// NOTE: the sample output is not the unique output format of the test program. The real output
// format depends on how you design the toString() methods in each class. But make sure that your
// program will print out as much information about each object’s fields as possible, including the
// Person
// Instructor
// Employee Student
// inherited fields and the fields defined in its own class.
// HINT:
// o There is NO main method in any of these 4 classes
// o To make sure ID is unique across the objects, declare a static “LAST_ID” in the Person
// class.
// o Read descriptions in test.java VERY CAREFULLY for better
// understanding!
// Submit your Person.java, Emloyee.java, Student.java and Instructor.java files
// Appendix 1: Test Program
/*
* Lab 2 Program to test the Person, Employee, Student, and Instructor classes.
*/
public class Lab2_Test
{
public static void main(String[ ] args)
{
// uncommenting the following line should produce a compile error.
// This is for testing of an abstract class.
// Person p = new Person("George");
final int MAX_HEADCOUNT = 20;
Person[] person_array = new Person[MAX_HEADCOUNT];
// A student named Peter
person_array[0] = new Student("Peter");
// An instructor named Peter
person_array[1] = new Instructor("Peter");
// An instructor named Sandy and her salary
person_array[2] = new Instructor("Sandy", 25000);
// A janitor named Bob
person_array[3] = new Employee("Janitor Bob");
// A student named Tom and his instructor is Peter.
// The constructor needs to do three things:
// 1: sets this student’s “TeacherName” field to be “Peter”,
// 2: finds out the ID of the 1st instructor
// who exists in the person_array so far and named "Peter",
// and assign it to this student's “TeacherID” field.
// Set it to be 0 if no instructor named Peter is found in the person_array so far
// 3: records this student’s ID in the instructor’s StudentArray if such an instructor is found
// right after executing the following statement
// person_array[4].TeacherID = 2
// person_array[4].TeacherName = “Peter”
// person_array[1].StudentArray[0] = 5
person_array[4] = new Student("Tom", "Peter", person_array);
// A student named Maggie and her instructor is Susan
// right after executing the following statement
// person_array[5].TeacherID = 0
// person_array[5].TeacherName = “Susan”
person_array[5] = new Student("Maggie", "Susan", person_array);
// An instructor named Susan and her salary
person_array[6] = new Instructor("Susan", 40000);
// After all objects are created,
// instructors need to fill their students arrays,
// and some students need to fill their TeacherIDs now,
// since there may exist cases that when a Student object is created with instructor’s name,
// the corresponding Instructor object hasn’t been created and is not in the person_array.
// For example, person_array[6] is created after person_array[5].
// You need to record person_array[5]’s ID in person_array[6]’s studentArray field,
// and record person_array[6]’s ID in person_array[5]’s TeacherID field.
// Note: if there are more than one Instructor objects
// having the same names as a Student object’s TeacherName,
// it’ll always be the first one’s ID assigned to the Student object’s TeacherID
Instructor.findStudents(person_array);
System.out.println("ID and name of all personnel in the array");
for (int i = 0; i < Person.getMaxID(); i++)
{
System.out.println(person_array[i].getId() + ":" + person_array[i].toString());
}
}
You are trying to print using this:
for (int i = 0; i < Person.getMaxID(); i++)
{
System.out.println(person_array[i].getId() + ":" + person_array[i].toString());
}
But, the getMaxID() method in your Person class returns a hardcoded 0, so this loop will never iterate, and your print statement will never be reached.
EDIT: it makes no sense to even check for a maxId. Check against the length of the array:
for (int i = 0; i < person_array.length; i++)
{
System.out.println(person_array[i].getId() + ":" + person_array[i].toString());
}

How do I create objects using more than one constructor?

I wrote the following code and driver program but I am not sure how to create bank account objects using both constructors. One constructor takes an initial balance and the second constructor opens an account with no money. Also, should the accountBalance include validity checks?
Optionally, I could do the following:
Include a fee as part of what describes a bank account. Update the BankAccount class as necessary. The user should be able to set the fee amount for each account and add the fee through a method. Add code to the driver program to demonstrate the fee functionality. (Could someone explain to me what this is asking)
//Bank Account class
import java.text.NumberFormat;
public class BankAccount {
private String ownerName;
private String accountId;
private double accountBalance;
public BankAccount(String ownerName, String accountId, double accountBalance) {
this.ownerName = ownerName;
this.accountId = accountId;
if(accountBalance >= 0) {
this.accountBalance = accountBalance;
} else {
System.out.println("Due to your negative account balace, you will be issued a fee.\n");
}
}
public BankAccount(double accountBalance) {
accountBalance = 0;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public double getAccountBalance() {
return accountBalance;
}
public void setAccountBalance(double accountBalance) {
if(accountBalance >= 0) {
this.accountBalance = accountBalance;
} else {
System.out.println("Due to your negative account balace, you will be issued a fee.\n");
}
}
public void withdraw(double amount) {
if(amount > 0 && amount < accountBalance) {
accountBalance -= amount;
} else {
System.out.println("Invalid withdraw amount! Please try again.\n");
}
}
public void deposit(double amount) {
if(amount > 0) {
accountBalance += amount;
} else {
System.out.println("Invalid deposit amount! Please try again.\n");
}
}
public String toString() {
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
return "Account Owner's Name: " + ownerName + "\n" + "Account ID: " + accountId + "\n" +
"Balance in the account: " + currencyFormatter.format(accountBalance);
}
}
//Driver Program
public class BankAccountDriver {
public static void main(String[] args) {
BankAccount myAccount = new BankAccount("Smith", "123jahgsd", 1200);
myAccount.withdraw(0.453);
myAccount.deposit(1000.1);
System.out.println(myAccount);
}
}
All nice answers, but they actually "miss" the "real" issue; and that is: you don't put down constructors because you can.
You create the code that is required to fulfill your requirements. In other words: you step back; and you think up respectively design the "intended use cases" for your bank account class.
And things to consider there: you avoid classes that can be created using such different paths.
Example: it is extremely dangerous to allow for empty id / owner fields. That leaves those fields with null values; and that means that you either need a lot of checking here and there; and if you forgot that here or there; you will run into NullPointerExceptions sooner or later (rather soon).
And keep in mind: your objects are meant to represent (model!) "reality". In reality, a bank account doesn't go without an owner; or an id.
In that sense, a sane implementation of your class would much more look like:
public class BankAccount {
private final String owner;
private final String id;
private double currentBalance;
public BankAccount(String owner, String id) {
this(ownwer, id, 0);
}
public BankAccount(String owner, String id, double currentBalance) {
this.owner = owner;
...
Notes here:
You want to prevent owner/id to be changed, so you make them final; and thus you also don't have setter methods for those fields
In a real world solution, you would not use Strings to represent names or ids, but distinct classes
You would also never ever use double to represent currency. This is a superbasic thing: money should not be represented using floating point numbers! (You would be looking towards to the BigDecimal class; or simply using int instead of double (and represent 1.75 $ as 175 cent)
And just a glance of real real world: nowadays, you don't model a bankaccount to have a "current balance". Instead, a bank account might be affiliated to a history of events (denoting deposits and pay-off transactions).
Final point: for your current exercise, that kind of "validation" for withdrawl/deposit is "okay"; in the "real world" validation would probably happen in many other places, too. (coming back to my initial statement: it all depends on your model; a simple model could say that a bank account itself is "validating" things; but a more realistic solution is that you have other components that deal with "rules", "laws" and all kinds of topics that do "validation").
You can do like this:
public BankAccount(String ownerName, String accountId, double accountBalance) {
this.ownerName = ownerName;
this.accountId = accountId;
this.accountBalance = accountBalance;
}
public BankAccount() {
this("some default name", "some default id", 0.0);
}
If you want to create a BankAccount with a zero balance then
public BankAccount(String ownerName, String accountId, double accountBalance) {
this.ownerName = ownerName;
this.accountId = accountId;
this.accountBalance = accountBalance;
}
public BankAccount() {
this.accountBalance = 0;
}
You can instantiate them as
BankAccount mine = new BankAccount("Scary", "123", 1000000.00);
BankAccount empty = new BankAccount();
edit
If you choose to construct a method with the second method, the id and owner would also be null and maybe not very useful
You can't create one bank account object using both constructors. You only call one of the two constructors to create a new object. So you either do:
BankAccount account = new BankAccount("Sweeper", "ABCDEF", 10000);
or:
BankAccount account = new BankAccount(100000);
Note that your second constructor's parameter is pointless because you initialize the balance to 0 no matter what the parameter is:
public BankAccount(double accountBalance) {
accountBalance = 0;
}
I think this makes more sense:
public BankAccount() {
this.accountBalance = 0;
}
As for your second question, I will give you some tips.
You need to add a new field to the class, called fee. Add getters and setters for it.
You make objects depending on which constructor you want to use. For example, to use the first constructor you need three parameters like so,
BankAccount first = new BankAccount("Bob", "ID45", 400.50);
and to use the second constructor you only need one parameter, the balance, like so,
BankAccount second = new BankAccount(400.50);
They'll both make instances of BankAccount except the difference is that on creation, the first bank account will have fields ownerName and accountId filled out while the second bank account will have those fields set to empty String values. However, the second object will have a balance of 0 unlike the first object's balance of 400.5
EDIT: Like user ScaryWombat suggested, there is a flaw in your second constructor because if you want to define an object with a balance of 0 then there's no point in adding a balance parameter. Also, in this case it would be advisable to give default values to your other fields as well,
public BankAccount() {
ownerName = "unknown";
accountId = "unknown";
accountBalance = 0;
}
So now when you create an instance of BankAccount with this constructor, it'll have the default values, "unknown", "unknown", and 0.
BankAccount third = new BankAccount();
Also, for the fee part, all you have to do is not only create another field in your BankAccount class called fee but also make a setter method to allow the user to set its fee,
private double fee;
.
.
.
public void setFee (double fee) {
this.fee = fee;
}
And in the main method, the user can access it with the following,
BankAccount account = new BankAccount("Fred", "ID145", 400);
account.setFee(15); //this will set the fee to 15

Minor issue when working with extended classes in Java

edit: this was entirely my error, likely due to rushing things at 4am. The code was technically sound and working fine, though thank to the comments I have removed some redundancy to make things a bit smarter.
I'm working on a class project that deals with Java super/subclasses and inheritance. While 90% of the code works just fine, one minor thing doesn't seem to want to work and I'm a bit perplexed as to why. Basically, we're creating a new class called CompactDisc that contains information such as product code, Description, Price, and Artist. When the user enters the appropriate code (sgtp), the console will output the information. Unfortunately the Artist line is always blank, despite giving it data. While there are other classes involved with this project, I'll will only post the ones I feel are important.
ProductApp.java:
import java.util.Scanner;
public class ProductApp
{
public static void main(String args[])
{
// display a weclome message
System.out.println("Welcome to the Product Selector\n");
// perform 1 or more selections
Scanner sc = new Scanner(System.in);
String choice = "y";
while (choice.equalsIgnoreCase("y"))
{
System.out.print("Enter product code: ");
String productCode = sc.next(); // read the product code
sc.nextLine(); // discard any other data entered on the line
// get the Product object
Product p = ProductDB.getProduct(productCode);
// display the output
System.out.println();
if (p != null)
System.out.println(p.toString());
else
System.out.println("No product matches this product code.\n");
System.out.println("Product count: " + Product.getCount() + "\n");
// see if the user wants to continue
System.out.print("Continue? (y/n): ");
choice = sc.nextLine();
System.out.println();
}
}
}
Product.java:
import java.text.NumberFormat;
public class Product
{
private String code;
private String description;
private String artist;
private double price;
protected static int count = 0;
public Product()
{
code = "";
description = "";
price = 0;
}
public void setCode(String code)
{
this.code = code;
}
public String getCode(){
return code;
}
public void setArtist(String artist)
{
this.artist = artist;
}
public String getArtist(){
return artist;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setPrice(double price)
{
this.price = price;
}
public double getPrice()
{
return price;
}
public String getFormattedPrice()
{
NumberFormat currency = NumberFormat.getCurrencyInstance();
return currency.format(price);
}
#Override
public String toString()
{
return "Code: " + code + "\n" +
"Description: " + description + "\n" +
"Price: " + this.getFormattedPrice() + "\n";
}
public static int getCount()
{
return count;
}
}
CompactDisc.java:
public class CompactDisc extends Product
{
private String artist;
public CompactDisc()
{
super();
artist = "";
count++;
}
#Override
public void setArtist(String artist)
{
this.artist = artist;
}
#Override
public String getArtist(){
return artist;
}
#Override
public String toString()
{
return super.toString() +
"Artist: " + artist + "\n";
}
}
ProductDB.java:
public class ProductDB
{
public static Product getProduct(String productCode)
{
// In a more realistic application, this code would
// get the data for the product from a file or database
// For now, this code just uses if/else statements
// to return the correct product data
Product p = null;
if (productCode.equalsIgnoreCase("java") ||
productCode.equalsIgnoreCase("jsps") ||
productCode.equalsIgnoreCase("mcb2"))
{
Book b = new Book();
if (productCode.equalsIgnoreCase("java"))
{
b.setCode(productCode);
b.setDescription("Murach's Beginning Java");
b.setPrice(49.50);
b.setAuthor("Andrea Steelman");
}
else if (productCode.equalsIgnoreCase("jsps"))
{
b.setCode(productCode);
b.setDescription("Murach's Java Servlets and JSP");
b.setPrice(49.50);
b.setAuthor("Andrea Steelman");
}
else if (productCode.equalsIgnoreCase("mcb2"))
{
b.setCode(productCode);
b.setDescription("Murach's Mainframe COBOL");
b.setPrice(59.50);
b.setAuthor("Mike Murach");
}
p = b; // set Product object equal to the Book object
}
else if (productCode.equalsIgnoreCase("txtp"))
{
Software s = new Software();
s.setCode("txtp");
s.setDescription("TextPad");
s.setPrice(27.00);
s.setVersion("4.7.3");
p = s; // set Product object equal to the Software object
}
else if (productCode.equalsIgnoreCase("sgtp"))
{
CompactDisc c = new CompactDisc();
c.setCode("sgtp");
c.setDescription("Sgt. Pepper's Lonely Hearts Club Band");
c.setPrice(15.00);
c.setArtist("The Beatles");
p = c; // set Product object equal to the CompactDisc object
}
return p;
}
And the output. As you can see Artist is empty:
Welcome to the Product Selector
Enter product code: sgtp
Code: sgtp
Description: Sgt. Pepper's Lonely Hearts Club Band
Price: $15.00
Artist:
Product count: 1
Continue? (y/n):
I have a hunch I did something wrong in ProductDB.java, but I could be wrong. Thanks in advance.
I cannot reproduce your error. I get the result:
Welcome to the Product Selector
Enter product code: sgtp
Code: sgtp
Description: Sgt. Pepper's Lonely Hearts Club Band
Price: 15,00 €
Artist: The Beatles
Product count: 1
Continue? (y/n):
The artist field of Product is hidden by the CompactDisk one. You should really change it to have a reasonable design. But I don't see why this shouldn't work.
Your problem exists because of the declaration
Product p
and later became
Product p = new CompactDisc();
That line means, your variables still refer to type Product and the methods from CompactDisc
Change
#Override
public String toString()
{
return super.toString() +
"Artist: " + artist + "\n";
}
to
#Override
public String toString()
{
return super.toString() +
"Artist: " + this.getArtist() + "\n";
}
When you are printing a varaible it still points to the LHS of the declaration and when you access a method it belongs to RHS.
As a side note, you have a design issues (commented the same earlier) as well by having multiple artist variables in parent and aswell as child. remove that at one level and make your program more clear.
There really shouldn't be an artist field nor a setArtist() in Product.
What happens here is that you can override a method, but you can't override a field, just hide it. And when you access fields, it depends on the type of reference, not on the actual class of the object. Since there is nothing in the artist field that was hidden by CompactDisk when you constructed it, you're getting an empty field.
Since p is a Product which has an artist field, when you call the toString method you are getting the value which is contained in his artist field, which is the empty string.
This happens primarily because you can't override a field. You are hiding the child field with the parent field.
Within the subclass, the field in the superclass cannot be referenced by its simple name, same is true for the parent class.
Since you are not using artist in Product in strange ways, I suggest to get rid of it in the Product class and use the CompactDisk one.

how would I use an if statment to change the value of an attribute?

I want to be able to give a specific value to discount depending on certain requirements like the following age: > 25 and profession = teacher / professor get 10% discount, age < 25 and gradepoint > 7 get 25% discount
this is my code so far I am using double OO paradigm:
public class customer {
//attribute definitions
private String name;
private String address;
private String profession;
private Integer age;
private Integer gradepoint;
private double discount;
//constructor
public customer(String newName, String newAddress, String newProfession, Integer newAge, Integer newGradepoint, double newDiscount)
{
setName(newName);
setAddress(newAddress);
setProfession(newProfession);
setAge(newAge);
setGradepoint(newGradepoint);
setDiscount (newDiscount);
}
//getters
public String getName()
{ return name;}
public String getAddress()
{ return address;}
public String getProfession()
{ return profession;}
public Integer getAge()
{ return age;}
public Integer getGradepoint()
{ return gradepoint;}
public double getDiscount()
{ return discount;}
//setters
public void setName (String newName)
{ name = newName;}
public void setAddress (String newAddress)
{ address = newAddress;}
public void setProfession (String newProfession)
{ profession = newProfession;}
public void setAge (Integer newAge)
{ age = newAge;}
public void setGradepoint (Integer newGradepoint)
{ gradepoint = newGradepoint;}
public void setDiscount (double newDiscount)
{ discount = newDiscount;}
//methods
}
Would I need to create a sub class called discount or each type of discount? or I can write a method directly into this customer class to control the discount?
write a method directly into this customer class to control the discount?
This. Make it a calculated field. Kill setDiscount function, kill discount variable, and make the getDiscount function into something like:
public double getDiscount() {
if (...) return ...;
if (....) return ...;
...
}
...unless you want to have this as the default discount, and still allow modification, in which case keep discount as a property, and move this whole logic into the constructor, having conditional setDiscount() calls.
Your getDiscount function would ideally do the calculation and return the appropriate discount for the current object. For example:
public double getDiscount()
{
if (getAge() < 25 && getGradepoint() > 7)
{
return .25;
}
else if // other logic...
}
Although not the simplest solution, I would abstract the discount calculation to a separate interface and class as well as having an override discount value in the customer object.
E.g.
public interface DiscountManager<T>
{
public double getDiscount(T discountObject);
}
public abstract class AbstractCustomerDiscountManager extends DiscountManager<Customer>
{
public double getDiscount(Customer customer)
{
if (customer.hasCustomDiscount()) { return customer.getDiscount(); }
else { return calculateDiscount(customer); }
}
public abstract double calculateDiscount(Customer customer);
}
public class DefaultDiscountManager extends AbstractCustomerDiscountManager
{
public double calculateDiscount(Customer customer)
{
double discount = 0;
if ((customer.getAge() != null) && (customer.getAge() < 25)) { discount += 25; }
...
return discount;
}
}
Probably over time different rules evolve. At the spot where the discounting takes place, in the order, the discount and and a reference to the rule applied should be stored together.
This kind of business logic could have its own class. A generic solution would even be to store the rule as scriptable code (BeanShell = Java, or JavaScript) and use java's scripting API. So that this kind of business logic resides more with the business managers, and the rules can be presented and edited.

Categories