Library System: Borrowing - java

I do not know how to do the borrowHolding() in the Library Menu I have to create.
So the purpose of the borrowHolding() is for members to be able to borrow books or videos.
This is a just a sample data of the array:
member[0] = new StandardMember("ID", "Name");
member[1] = new PremiumMember("ID", "Name");
holding[0] = new Book("ID", "Title");
holding[1] = new Video("ID", "Title", loanFee);
This is the borrowHolding() method in the TestLibrary class: (the array is in the TestLibrary class too)
public static void borrowHolding(){
String option;
option = input.next();
do{
Scanner scan = new Scanner(System.in);
int tempId = 0;
System.out.println("Enter your ID: ");
String searchID = scan.next();
for(int i = 0; i < member.length; i++){
if(member[i].getID().equals(searchID)){
tempId = i;
}
}
So for the method, I tried to write a code that will search through the array to find the memberID that wants to borrow. It is not completed yet because I believe I am not doing it correctly
There is a Member class that contains
public class Member{
public Holding[] getCurrentHoldings(){
}
}
from the name of the method, it is used to store the holdings of the members that borrowed. So if member 1 borrows a book, that book will be stored inside the array, i think. I was thinking of using an ArrayList for this method, but not sure if it would make sense.
To borrow a book or video, there are certain conditions to be able to borrow, but I do not know how to implement this into the borrowHolding(). One of the condition are in the Holding class.
public class Holding{
public boolean borrowHolding(){
if(status == true && isOnLoan() == false)
borrowDate = newDateTime(); //this is to get the time when the book or video is borrowed
return true;
}else
return false;
}
}
And there is another condition in the Member class is that the Member must have enough credit to borrow. A book loan fee will cost $10 and a video will vary from $4 or $6.
I think I wrote a few information that is not needed but I guess its better than less information.
My problem is what do I do to the borrowHolding() method in the LibraryMenu? how do I make that if a member wants to borrow a holding, the holding will go under the member's array in the member class
public class Member{
public Holding[] getCurrentHoldings(){
}
}
with the condition from the holding class if it is met, and while executing the borrowHolding method, the method from the member class will be able to subtract the member credit by the loan fee from the book or video. is it possible?
public class Member{
private int credit = 30;
public int calculateRemainingCredit(){
credit = credit - //(the loan fee from the book or video class)
}
}

If your intentions are to add a holding to the member class then this is possible. I would suggest adding an ArrayList of Holding's rather than a regular array because it seems as if the size is going to be constantly changing.
public class Member{
private ArrayList<Holding> currentholdings; // you may need to import the arraylist
private int credit;
public void init(){ // goes in constructor
currentholdings = new ArrayList<Holding>();
credit=0;
}
public void addHolding(Holding newholding){ // adds a new holding to the members array
currentholdings.add(newholding);
credit-=newholding.getFee(); // will need to add a fee variable to the holding class;
}
}
And as for checking to see whether or not the member has enough "credit", that can be done in the borrowHolding() method right after you identify the index of the array. I would just recommend adding a parameter of the member to the borrowHolding() method so you can easily access the variables from that member.
if(member[i].getID().equals(searchID)){
tempId = i;
int tempHolding; // index of whatever holding you wanted (could get this from the scanner)
if (holding[tempHolding].borrowHolding(member[tempId])){ // check status
member[tempId].addHolding(holding[tempHolding]); // they have passed the req. so you can add the holding
}
break;
}
Hope this answered your question.

Related

Accessing an object of a class from another class object

Starting of I want to apologise for my english as I'm not a native speaker. The title might be a bit off since I was not sure how to phrase it but hopefully it will come through once I show my code.
The problem I'm phasing is I want to use the shop class to handle any purchases while storing the money variable on the player class.
Is there any way to access the money integer of the player class without creating an object of the player class in the shop class ?
I was thinking about using a static integer to store the data in but from what I've read online its bad practice to use static datatypes.
public class Beta {
public static void main(String[] args) {
Player p1 = new Player("Test");
Shop s1 = new Shop();
p1.setMoney(100);
s1.clerk(p1.getMoney());
}
}
public class Player {
private int money;
private String name;
public Player(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int x) {
this.money +=x;
}
}
public class Shop {
private int money;
public void clerk(int x) {
this.money = x;
if (this.money >= total) {
question4 = false;
System.out.println("Your purchase was successful!");
if (blue > 0) {
this.addInventory("Blue", blue);
}
if (red > 0) {
this.addInventory("Red", red);
}
if (green > 0) {
this.addInventory("Green", green);
}
}
else {
question4 = false;
System.out.println("Sorry you cant afford that!");
}
}
}
}
So I cut down my code to show you only the essential parts.
What I want to do is access p1:s money variable from the player class from within the Shop class.
So far I have been passing the variable when calling it from main. Is this the only option I have or can it be accessed in any other way ?
Any help would be much appreciated!
I believe the option that follows Object-Oriented Programming principles best is to pass the actual Player in as an argument, instead of just the money.
Basically, passing just the player's money in instead of the player themselves is like just handing your wallet over to the cashier. You wouldn't do that, right?
This way, the clerk can ask the customer if they have enough money by calling player.getMoney(), and the customer can tell them the answer.
After making the purchase, the player can remove the money from their wallet themselves when the clerk asks them to via player.setMoney().
Now, you asked in a comment about "passing the actual player as an argument without creating a new object of the player class." Java passes arguments by value, and all objects' values are simply the address that hold the information for that particular instance.
So for Player p1 in Beta, let's pretend all of p1's information is stored in a block starting at...let's say, address 21343. In this case, the variable p1 only contains that single number, 21343.
Since Java passes by value, then when you call s1.clerk(Player player), the player variable will also contain 21343. Since it's editing the items contained at the same address, you've essentially passed on p1 itself instead of creating a new Player. In short, the clerk and the main method work with the same object.
The fact that Java passes by value is also why passing just the player's money in doesn't adjust it automatically: The money is an int rather than an object. Since it's an int, when you pass it to the clerk, you're just saying "Hey, clerk, this is the amount of money being worked with." But the clerk has no idea who the money belongs to, so while it can take money, or even give it some, it's essentially just setting it down on the counter, and it's the responsibility of the player to pick it up from there when they're done. By passing in the player instead, the clerk knows who the money belongs to because it's actually asking the player how much money they have.
Another potential solution would be to make p1 and s1 static variables in the Beta class. It'd look something like this:
public class Player
{
public static Player p1;
public static Shop s1;
public static void main(String[] args)
{
p1 = new Player("Test");
s1 = new Shop();
p1.setMoney(100);
s1.clerk(p1.getMoney());
}
}
From there, you'd import the Beta class in Shop, then call Beta.p1 in Shop to access p1.
Hope this helps!

How can i make constructor without fields with enum?

I don't have idea how to add to array enum. I made constructor using fields with enum and its works, but I don't know how to make it in constructor without field. I hope that you understand what Im thinking about. In my code I comment where I think i have problem.
I've got:
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
System.out.println("name of producer:");
String producername = Main.sc.nextLine();
System.out.println("name of model:");
String modelname = Main.sc.nextLine();
System.out.println("ram:");
int ram = Main.sc.nextInt();
System.out.println("cpu:");
String cpu = Main.sc.nextLine();
cpu = Main.sc.nextLine();
System.out.println("components:");
System.out.println("how many components do you want to add?");
int z = Main.sc.nextInt();
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = //<-- how to add enum in array?
}
setProducerName(producername);
setModelName(modelname);
setRam(ram);
setCpu(cpu);
setComponents(com);
}
My constructor using field is like that and it works.
public Laptop(String ProducerName, String ModelName, int Ram, String Cpu, Components... components) {
super();
this.ProducerName= ProducerName;
this.ModelName= ModelName;
this.Ram= Ram;
this.Cpu= Cpu;
this.components= new Components[components.length];
this.components= Arrays.copyOf(components, components.length);
}
Please help.
You could get the enum value by its name.
public enum Components {
WIFI, BLUETOOTH, CAMERA, SSD
}
public Laptop(){
...
Components[] com = new Components[z];
for(int i=0; i<com.length;i++){
com[i] = Components.valueOf(Main.sc.nextLine());
}
...
}
I'm not 100% clear what you're asking, but you can get an array filled with your enum constants from the enum itself: Components.values() will return an array of all the enum constants. It will essentially return:
new Components[]{Components.WIFI, Components.BLUETOOTH,
Components.CAMERA, Components.SSD}
Side recommendation: don't use Scanner inside of your Laptop constructor, and in fact, get all user interface code out of all constructors and instance methods of that class. All user interface code belongs elsewhere.

Looping the wrong way?

The assignment for my class asks me to create a program that tells a supermarket which customer, on a daily basis, has spent the most money in the store. The program must find this customer and display their name.
Goals of assignment - To work with multiple classes, work with ArrayLists and apply the knowledge gained.
My question:
How should I loop my two output statements in my main class? Is that right in my main method? I need it to loop until the sentinel is used.
How is this going to affect my sentinel?
What type of questions should I be asking myself when dealing with loops? I'd like to think I'm overthinking this portion.
I really want to understand what I am doing here, so any help in the right direction would be appreciated! Thanks, in advance, for taking the time to help me out!
import java.util.Scanner;
public class main {
public static void main(String[] args) {
System.out.println("* * * * * THE SUPERMARKET * * * * *");
System.out.println(" Written by Nate Irwin");
System.out.println();
double finalTotal = -1;
String anAccountName;
Scanner input = new Scanner(System.in);
Store store = new Store();
do {
System.out.println("Enter the customer name: ");
if(input.hasNextLine()){
anAccountName = input.nextLine();
System.out.println("Enter customer total price, hit 0 to QUIT: ");
finalTotal = input.nextDouble();
store.addAccount(anAccountName, finalTotal);
System.out.println();
}
} while (finalTotal != 0);
System.out.println(store.getHighestCustomerTotal() + " has spent the most with us today!");
}
}
Store class:
import java.util.ArrayList;
public class Store {
// Creates an ArrayList.
private ArrayList<CustomerAccount> accounts = new ArrayList<CustomerAccount>();
//
public void addAccount(String anAccountName, double finalTotal) {
accounts.add(new CustomerAccount(anAccountName, finalTotal));
}
// Gets the HIGHEST customer total.
public String getHighestCustomerTotal() {
CustomerAccount highest = accounts.get(0);
for (int i = 1; i < accounts.size(); i++) {
if (accounts.get(i).getTotal() > highest.getTotal())
{
highest = accounts.get(i);
}
}
return highest.getAccountName();
}
}
CustomerAccount class:
public class CustomerAccount {
// Variables defined to this class.
private String accountName;
private double total;
// Constructor.
public CustomerAccount(String anAccountName, double finalTotal) {
accountName = anAccountName;
total = finalTotal;
}
// Gets total from each customer.
public double getTotal() {
return total;
}
// Gets a customer's name.
public String getAccountName() {
return accountName;
}
}
I think your approach is fine, it gets the job done.
I'm not too sure what you're asking by saying how should you loop the two output statements, followed by if it should be in the main method. From what I understand, and by looking at your code, running this input loop is perfectly fine from the main class. The do-while is fine although I'd move the first 'introductory' output outside the loop so you don't see it every time the loop reiterates.
Also, I notice you're not actually calling/instantiating the Store class in your main method, there's no data being added to the Store class for when it iterates through the accounts ArrayList.
As far as the answer that stated a more "modern" approach, I think the for loop you used is fine. I think the person was referring to the for-each loop. It doesn't really matter how you loop through it with the little amount of data you have.
There's some error in the logic for that loop. The getHighestCustomerTotal() is referencing an empty accounts ArrayList. You declared an ArrayList within the Store class and tried to loop through it but it's empty unless you called the addAccount() method from your main method at some point, so you'd need some error checking on that.
Your loop in main:
Doesn't really use the data you type in... One would expect this data to be used to create CustomerAccount instances
Has a completely unnecessary while(Condition) test at the end. This kind of loop is normally done with a While True and some test in the loop breaks out of the loop.
In getHighestCustomerTotal()
you can use a more "modern" form of the for() where you iterate elements of the list directly instead of iterating the index.

How to get variables from different classes?

So i'm working on this project and i'm having trouble moving variables from one class to the other. The goal of this tiny software is to have the user input 2 pieces of information, one's a string and the other is an int. I also have 2 classes, one to retrieve the information and the other one to calculate it.
This is the first class called Software:
import java.util.Scanner;
public class Software
{
public Scanner softwareName;
public Scanner devicesAmount;
public Software()
{
devicesAmount = new Scanner(System.in);
softwareName = new Scanner(System.in);
}
/**
*Gets the information from the user to later on process
*/
public void InfoGet()
{
Devices findDevices= new Devices();
Devices findNumber= new Devices();
String softwareName;
int devicesAmount;
Scanner sc= new Scanner(System.in);
System.out.println("Welcome to the Software License Calculator");
System.out.println("Please type in the name of the Software:");
softwareName = sc.nextLine();
System.out.println("");
System.out.println("Please type in the number of devices that have the software:");
devicesAmount=sc.nextInt();
findDevices.Calculations(devicesAmount);
findNumber.getNewDevices();
sc.close();
System.out.println(softwareName+ " & "+ findNumber);
}
}
And here's the second class called Devices:
public class Devices
{
public int NewDevices;
public String softwareName;
/**
* Gets number of Devices to preform the calculations of removing 1000 users
*/
public static void Devices()
{
Software getDevices= new Software();
getDevices.InfoGet();
}
public void Calculations(int devicesAmount){
if (devicesAmount>=1000){
NewDevices= devicesAmount - 1000;
}
else{
NewDevices=devicesAmount;
}
}
}
dunno why I post as user when I'm on my movil device, but to the point:
First of all in the class Software you have 2 objects "Device", following the MVC arquitecture you should only declare 1 controller object for the view class, to start I recommend you to only declare 1 Device for Software class, like this and we're gonna make the variables protected just cause they should be private or protected to respect the encapsulation:
public class Software {
protected Devices devices;
protected Scanner softwareName;
protected Scanner devicesAmount;
... }
I recommend you to do the same for the Devices class variables.
Then we're gonna build a proper constructor for Devices class so we can move the values through classes:
public Devices (String softwareName) {
this.softwareName = softwareName;
this.newDevices = 0;
}
So we can have this values at the Devices class. Then we need to add the getter for newDevices and adding the toString method to the Devices class so you can print the object.
public int getNewDevices() {
return newDevices;
}
public String toString() {
return softwareName + " & " + newDevices;
}
Then we're gonna move some stuff at the Software InfoGet method to build de devices correctly and printing it.
public void InfoGet() {
String softwareName;
int devicesAmount;
Scanner sc= new Scanner(System.in);
System.out.println("Welcome to the Software License Calculator");
System.out.println("Please type in the name of the Software:");
softwareName = sc.nextLine();
System.out.println("");
System.out.println("Please type in the number of devices that have the software:");
devicesAmount=sc.nextInt();
devices = new Devices(softwareName); // So we initialize the object.
devices.Calculations(devicesAmount);
sc.close();
System.out.println(devices.toString()); // Here we just call the toString() method we build to print the values.
}
We didn't use the getNewDevices() method, but building getters and setters for controller classes is a good practice in general ;).
I highly recommend you to read about MVC (model-view-controller) if you wanna build your proyect in a "standar" way.
To solve your problem you can add to each class the getters and setters for each variable you need to move so you can move values between classes.
Like this for setters:
public void setValue(Object value) {
this.value = value;
}
And this for getters:
public Object getValue() {
return this.value;
}
It's very confusing between Scanner, Device, Software, classes and objects with the same name upper or lower cases.
I should recommend to rename you classes and variable clearly.
Some further advices:
why keeping Scanner as variables ? It's not data, it media to get it.
why note keeping data ? like softwareName (Scanner AND String).
I would
add two variables (softwarename and amount), private
keep them
add methods to Set and Get
Calculations() (and others) won't compile. Probably you need to add an argument to that method and you are done (?):
public void Calculations(int devices2){
...

How to expand a randomHuman constructor to take two types of objects?

I am a java-noob as I recently started to learn in a course.
I have created a class:Humans which have ability to store their name and age, and also a subclass Students which extends Humans and adds the Year they began there studies.
I have constructed a randomHuman constructor where I call it(in my main class) and create a list with the humans(with random name and age).
My problem is when i want to random 5 human non-students and 5 students and create this list, I'm not sure how to find out what type of object is sent to the random constructor, so i know if i should give it a year or not. And what type to tell the constructor to return.
I am sorry that this turned into an essay, but if anyone would be so kind to help then I would greatly appreciate it.
TLDR; How to expand a randomHuman constructor to take two types of objects?
Here is my main class:
public class Main {
public static void main(String []args){
Human newHuman = new Human( 18, "Tommy");
System.out.println("Age: " + newHuman.getAge());
System.out.println("Name: " + newHuman.getName());
System.out.println(newHuman.toString());
Human putte = new Human (25,"Putte");
System.out.println(putte);
//Varför blir det så?
//kanske lokal variabel
//Array RandomHumans
System.out.println(" ");
System.out.println("Array Human");
ArrayList<Human> myAl = new ArrayList();
for(int i = 0; i<15; i++){
Human xx =Human.randomHuman();
myAl.add(xx);
}
//Array RandomFysiker
for(int j = 0; j<myAl.size(); j++){
Human var = myAl.get(j);
System.out.println(var.toString());
}
System.out.println(" ");
System.out.println("Array Fysiker");
ArrayList<Fysiker> myAl2 = new ArrayList();
//puts the Fysiker in an array
for(int i = 0; i<15; i++){
Fysiker xx =Fysiker.randomHuman();
myAl2.add(xx);
}
//prints teh array
for(int j = 0; j<myAl2.size(); j++){
Fysiker var = myAl2.get(j);
System.out.println(var.toString());
}
}
}
and my Human class:
public class Human {
public String name;
public int age;
Human(int ageIn, String nameIn){ //Constructor
age=ageIn;
name=nameIn;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String toString(){
return "Name: " + getName() +"," + " Age: " + getAge();
}
//Random human
// Behöver ändra konstruktorn så att den kan kolla
// om objectet är Fysiker eller Human och sedan,
// Behandla dom olika
//Problem1: Hur kollar man? Föreslag if(obj instanceof Fysiker), men vad ska jag ha som obj
//Problem2: Vilken returtyp ska man då ha?
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// if(xx instanceof Fysiker){
//
// }
return new Human(randomAge,randomName);
}
}
and the subclass Fysiker(aka student):
/**
*
* #author Julian
*/
public class Fysiker extends Human{
public int schoolYear;
public Fysiker(int startYear,int ageIn, String nameIn){
super(ageIn, nameIn);
if (age>15){
if (startYear>2013){
} else if (startYear<1932){
} else {
schoolYear = startYear;
}
} else {
}
}
public int getYear(){
return schoolYear;
}
public String toString(){
return super.toString() +","+" Startyear: " +getYear();
}
}
Actually, your randomHuman() method, as mentioned in the comments, is not a constructor at all. It's a static factory method, although I'm sure you're not aware of what that means as yet.
Basically, a constructor is not a method at all and doesn't have a return type. What a constructor does is provide an initialization for a new instance of the class, created by using new, although it can do things that don't strictly initiate the fields of that object.
A method, in contrast, can return something. And in your particular case, the last line actually tells you exactly what it returns - it's calling new for the class Human, so it will return an object of class Human, never a Student.
In fact, the class Human is not aware of the class Student. In principle, you could write a subclass for a class, years after the parent class has been written. Parent classes don't need to know about their descendents. They just decide what they allow those descendents to change and what they don't allow them to change.
You could, in theory, put a method in Human that creates a Student instance. But I'm pretty sure that's not needed in the current situation.
What you probably want to do is fill a list of humans outside the definition of either Human or Student. Filling a random list is probably not part of "being a human" or "being a student" is all about, so you should just do it in your Main class, calling new Human() or new Student() as you wish and filling them as appropriate. Since you know which new you called, you also know whether or not to use a random year.
You could do it in a static method in your Main class, to signify that this is something you do for testing, and not really part of the logic of either a Human or a Student.
As for being able to tell which object you now got from the list - you can do that with instanceof. But you'll also need to typecast it to Student if you want to access its getYear() method.
However - and this is the neat thing about polymorphism - if you just call the toString() method, and don't even check the type of the object, you'll get it with the year if it's really a Student object, and without it if it's a plain Human object.
Let's assume your teachers actually want you to extend the randomHuman method so that it sometimes gives Human instances, and sometimes Students. When it gives Student, it should of course provide it with a year.
As I said above, this is called Tight Coupling between parent and subclass, and is not recommended. If I wanted to build another human subclass, such as Politician, I'd have to call you and ask you to release a new version of Human that also sometimes gives random Politicians. So, under protest, I'll explain how to do it.
Your existing function is:
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// if(xx instanceof Fysiker){
//
// }
return new Human(randomAge,randomName);
}
We change it like so:
public static Human randomHuman(){
String[] anArrayOfStrings={"Tom", "Jon", "Chris","Julian","Roberto","Sam","Lisa","Roxanne","Rebecca","Anton","Johannes","Antonella","Bianca"};
int randomAge = (int) (100*Math.random());
String randomName = anArrayOfStrings[(int)(Math.random()*anArrayOfStrings.length)];
Human result = null;
if ( Math.random() < 0.5 ) {
// With a probability of 50%, create a plain human
result = new Human( randomAge, randomName );
} else {
// Create a student. Start by calculating a random year.
int randomYear = (int) (Math.random()*(2013-1932) + 1932);
result = new Fysiker( randomYear, randomAge, randomName );
}
return result;
}
So, you decide that you want to make a plain human, and within the scope of that decision, you create it with new Human(...) and assign to the result variable.
If you decide to make a student, within the scope of that decision, you calculate a random year, and create it with new Fysiker(). You can assign it to the variable result because polymorphically, it's Human. But in reality, internally, it's a Student.
You return the result variable, which may contain either a Human or a Student at this point.
For determining what type the object instance is use either object instanceof class or object.getClass().equals(Clazz.getSimpleName())
For return type just use the superClass (or interface). You can always cast it to the child if needed.
If you want to create 5 class of each you need a boolean in the method declaration and call it 5 times each to be sure u will have 5 instances of each class.
public static Human randomHuman(boolean isHuman){
If this is not important u can add a random boolean and then call the constructor:
boolean isHuman = Math.random() < 0.5;
if(!isHuman){
int RandomYear = (int) (Math.random()*(2013-1932) + 1932);
// create student
} else {
// create human
}

Categories