I am new to Java and I need some help implementing OOP rules for projects that are similar to the Library model (Car rental model).
I have 2 classes:
public class Book
public class Customer
Simply put, my classes look like this:
public class Customer
{
public String fullName;
public String address;
/* Constructor */
public Customer(String fullName, String address) {
this.fullName = fullName;
this.address = address;
}}
and
public class Book
{
private String bookName;
private int pageNumber;
public Customer customer; //I think this needs to be fixed
/* Constructor */
public Book(String bookName, int pageNumber, Customer customer) {
this.bookName = bookName;
this.pageNumber = pageNumber;
// ... There I am not sure how to do something like: this.customer = customer ...
// there should be another constructor without customer as a parameter but i can deal with that cuz its easy
}}
Each instance of the Customer class represents a person who borrowed the book. Now what I am struggling to implement is: How do I pass an instance of Customer class as a parameter for a constructor of the Book class? I would like something like this:
// Constructor in Class Book:
public Book(String bookName, int pageNumber, Customer customer) {
this.bookName = bookName;
this.pageNumber = pageNumber;
this.customer = customer; //I think this needs to be fixed
}
Another question is how do I create a record of a book boorowed by Sarah Connor living in London? Is this implementation correct Book book1 = new Book("The Hobbit", 300, "Sarah Connor", "London")?
Basic solution
Basically, your approach was completely correct:
public Book(String bookName, int pageNumber, Customer customer) {
this.bookName = bookName;
this.pageNumber = pageNumber;
this.customer = customer;
}
However, as your comment shows, you are still lacking some very basic understanding of Java. Let's recap what you tried:
Book book1 = new Book("Harry Potter", 500, "Mike", "London");
Why wouldn't this work?
First, you pass in 4 parameters instead of 3. But let's assume that was a typo and ignore "London". Still, there is an issue: "Mike" is a String, but your constructor expects a Customer. Hence, your code should look like this:
Customer mike = new Customer("Mike Malony", "N13BJ London");
Book book1 = new Book("Harry Potter", 500, mike);
Since you asked in the comments, this can be done in one line as well:
Book book1 = new Book("Harry Potter", 500, new Customer("Mike", "London"));
Further issues and advice
Now your issue seems solved, but your code still isn't very... versatile. The reason is that your model is severely limited: you can only ever instantiate a Book if you pass in a Customer. But most libraries I know can have books that are not currently borrowed. Also, whatever your pageNumber seems to represent (a bookmark, possibly?), I assume an untouched book doesn't need this information. I would therefore suggest this:
public Book(String bookName) {
this.bookName = bookName;
this.pageNumber = 0; // 0 => no page bookmarked
this.customer = null; // null => book is available
}
Now you need a way to hand out a book to a customer and also to check its status. I suggest:
public void lend(Customer customer) {
this.customer = customer;
}
public void receiveBack() {
customer = null;
pageNumber = 0;
}
public boolean isAvailable() {
return (customer == null);
}
And to bookmark a page:
public setBookmark(int pageNumber) {
this.pageNumber = pageNumber;
}
Of course, this is still far from optimal. What if a customer wants to borrow several books? Should the books really hold the reference to the customer? There are several approaches to this. One would be to have a dedicated class that holds the associations of customers to books. Another would be to use some sort of collection in either Book or Customer. However, that's probably all beyond the scope of your task, so I'll leave it at the above.
If you want to declare your instance like this
Book book1 = new Book("The Hobbit", 300, "Sarah Connor", "London")
You will need to define your constructor of Book Class like this :
public Book(String bookName, int pageNumber, String fullname, String address) {
this.bookName = bookName;
this.pageNumber = pageNumber;
this.customer = new Customer(fullname, address); //I think this needs to be fixed
}
Or other option is to declare it like this
Book book1 = new Book("The Hobbit", 300, new Customer("Sarah Connor", "London"));
Related
I was going through refactoring book and couldn't understand these two techniques.
https://refactoring.com/catalog/changeValueToReference.html
And
https://refactoring.com/catalog/changeReferenceToValue.html
Can you please help me understand with an example in Java?
Assume you have two Customer objects/instances, customer1 and customer2. They are actually the same customer, with same ID and name. However they were read at different moments from the database or such. A new Customer() was called twice.
Customer customer1 = new Customer(13L);
Customer customer2 = new Customer(13L);
The refactoring would involve a factory method:
Customer customer1 = customerRepository.findById(13L);
Customer customer2 = customerRepository.findById(13L);
Examples of the latter is for instance JPA, an O/R mapping.
In it's very simplest form it just means switching between the following two options:
class Order
{
// constructor etc...
private String customerName;
public String getCustomerName() {return customerName;}
}
or
class Customer
{
// constructor etc...
private String name;
public String getName() {return name;}
public String setName(String name) {this.name = name;}
}
class Order
{
// constructor etc...
private Customer customer;
public String getCustomerName() {return customer.getName();}
}
Now when a customer's name can change, the 2nd solution is prefered, because you don't need to update the customerName member in every order.
However if a customer's name never changes, the 1st solution might be prefered, because you don't need to manage Customer objects somewhere.
Which version you want to chose and if you need to refactor depends on your actual application.
Strictly speaking, I'm not sure whether this conversion is possible in Java, since you don't have both references and values of objects in Java - all objects are references (which are passed by value).
However, one can consider this similar to the following example:
"Value":
class Order
{
private int orderNum;
private Customer customer;
Order(int orderNum, String customerString)
{
this.orderNum = orderNum;
this.customer = new Customer(customerString);
}
}
// elsewhere:
Order order1 = new Order(1, "I am a customer");
Order order2 = new Order(2, "I am a customer");
Order order3 = new Order(3, "I am a customer");
Order order4 = new Order(4, "I am a customer");
Here each Order has it's own Customer object, even when all or most of those Customer objects are the same.
The above is, of course, just an example. Passing all parameters of another object into a constructor is not good design.
Reference:
class Order
{
private int orderNum;
private Customer customer;
Order(int orderNum, Customer customer)
{
this.orderNum = orderNum;
this.customer = customer;
}
}
Customer customer = new Customer("I am a customer");
Order order1 = new Order(1, customer);
Order order2 = new Order(2, customer);
Order order3 = new Order(3, customer);
Order order4 = new Order(4, customer);
Here we can have a single Customer for many Orders (if we want).
I have two classes, Student and Book.
I want to store book name returned by student.getBook(that will return Set<Book>) into List<String>.
Student.java
public class Student {
private int id;
private String bookName;
//Setter and getter.......
}
Student.java
public class Student {
private int id;
private String student Name;
private Set<Book> books;
//Setters and Getters
}
Here is main method
public static void main(String[] arg){
Book b1= new Book(1, "art");
Book b2= new Book(2, "science");
Book b3= new Book(3, "bio");
Set<Book> b=new HashSet<>();
b.add(b1);
b.add(b2);
b.add(b3);
Student s=new Student (1, "std1",b);
//here I want to store bookName
//into List, some thing like
List<String> book=new
ArrayList<>(s.getBooks().getBookName());
}
Please help.....
This is where the Stream API comes in handy!
To turn a set of books (s.getBooks()) directly into a List<String> with book names, you just need to map and collect.
List<String> bookNames = s.getBooks().stream()
.map(x -> x.getBookName())
.collect(Collectors.toList())
This might look new to you, so I'll explain it bit by bit.
The stream method creates a Stream<Book>. This is so that you can do cool operations, like map, reduce and filter on the Set. Then we map the stream of books. map is just another word for "transform". Because you only want the book names, we transform each book in the stream into its book name. The x -> x.getBookName() describes how we want to transform it. It means "given a book x, we get the book name of x". And finally, we call collect, which "collects" everything in the stream and puts them back in a collection. In this case we want a List so we call toList().
Since s.getBookNames() returns the Set<Book>, you must iterate over the collection to fetch individual book's name and then save it to another List in your code named as book :
List<String> bookNames = new ArrayList<>(); // initialize a list for all the book names
s.getBooks().forEach(book -> bookNames.add(book.getBookName())); // iterate all the books and add their names to the above list
Also, this assumed few obvious things as pointed in comments as well,
private String student Name; // this variable either named as 'student or `name` or `studentName`
and the first model is for the Book.java instead of Student.java.
Someway, I see your modal definition for student is not good. Simply you can define Student modal as follow.
And create a separate public method in Student class to fetch the booknames.
public class Student {
private int id;
private String name;
private Set<Book> books;
public Student(int id, String name, Set<Book> b) {
this.id = id;
this.name = name;
this.books = b;
}
// all getter and setter.
public List<String> getBookNames(){
return this.getBooks().stream().map(x -> x.getName()).collect(Collectors.toList());
}
}
if you are using java1.8, as sweeper suggested you can use stream api to do your work.
public static void main(String[] args) {
Book b1 = new Book(1, "art");
Book b2 = new Book(2, "science");
Book b3 = new Book(3, "bio");
Set<Book> b = new HashSet<>();
b.add(b1);
b.add(b2);
b.add(b3);
Student s = new Student(1, "std1", b);
List<String> books = s.getBookNames();
System.out.println(books);
}
Unsure on how i'm supposed to add to an array, i've been asked to fill the array from a test file but define it in class Patient. Any ideas?
public class Patient
{
private String name;
private int id;
private int current = 1;
public Patient(String name, int id)
{
this.name = name;
this.id = id;
Patient[] patient = new Patient[100];
String[] Observations;
System.out.print(patient[0]);
}
public String addPatient(String name,int id)
{
Patient[current-1] = new Patient(name,id);
}
}
// extract from class PatientRecordSystem
public void addPatient()
{
String name = "James";
int id = 10122;
Patient patient = new Patient(name, id);
}
Your problem is that you are defining that list (or array) to hold Patient objects within the constructor of your Patient class.
That is simply wrong on many levels. First of all - one "Patient" should be exactly that - the representation of a single patient. When you go to the doctor and become a patient ... are you asked to know about 100 other patients around?! Then: that array that you define in the constructor ... just lives during the execution of the constructor. It simply goes away as soon as a call
Patient newPatient = new Patient( ... )
returns.
In other words: you want to think of another class that is responsible for "managing" multiple patients. And then you create "patient objects"; and tell the manager about them. And that "manager" is then using an array (or better some more dynamic List) in order to keep track of "managed" patients.
Whatever Andrew said is correct , just making it easy for you. Use below code
public class Patient
{
private String name;
private int id;
private int current = 1;
private Patient[] patient = new Patient[100];
public Patient(String name, int id)
{
this.name = name;
this.id = id;
String[] Observations;
System.out.print(patient[0]);
}
public String addPatient(String name,int id)
{
patient[current-1] = new Patient(name,id);
}
}
// extract from class PatientRecordSystem
public void addPatient()
{
String name = "James";
int id = 10122;
Patient patient = new Patient(name, id);
}
First you need to declare the array.
You can do something like:
Patient[] patients = new Patient[100];
if you know the size of the array.
If you want to build a dynamic array, because you don't know how many elements you are going to have, you can do something like that.
List<Patient> patients = new ArrayList<Patient>();
Then you can assign values to the array:
If you have declared a fixed array you can do something like that:
patients[0] = new Patient(name, id);
On the other hand, if you have declared a dynamic array, the code would look like:
patients.add(new Patient(name, id));
I'm fairly new to coding so just wondering if someone can point me in the right direction. I'm looking to set up a Library class containing an array or array list of Book objects that carry out appropriate functions such as adding a Book, editing a Books details, deleting a Book, returning a Book and loaning a Book.
So far I have created the following Book class
//Instance variables
private int BookID;
private String Title;
private String Author;
private boolean On_Loan;
private int Number_of_Loans;
//Constructor
public Book(int BookID, String Title, String Author, boolean On_Loan, int Number_of_Loans){
this.BookID = BookID;
this.Title = Title;
this.Author = Author;
this.On_Loan = On_Loan;
this.Number_of_Loans = Number_of_Loans;
}
//Mutator methods
public void setBookID(int BookID){
this.BookID = BookID;
}
public void setTitle(String Title){
this.Title = Title;
}
public void setAuthor(String Author){
this.Author = Author;
}
public void setOn_Loan(boolean On_Loan){
this.On_Loan = On_Loan;
}
public void setNumber_of_Loans(int Number_of_Loans){
this.Number_of_Loans = Number_of_Loans;
}
//Accessor methods
public int getBookID(){
return BookID;
}
public String getTitle(){
return Title;
}
public String getAuthor(){
return Author;
}
public boolean getOn_Loan(){
return On_Loan;
}
public int getNumber_of_Loans(){
return Number_of_Loans;
}
}
You need an ArrayList<Book> object! To create one:
ArrayList<Book> books = new ArrayList<> ();
To add an item to it,
books.add (yourBookObjectToBeAdded);
To change the books' properties, you need to get the book first,
books.get(theIndexOfTheBook);
It is recommended to store the book in a variable:
Book myBook = books.get(theIndexOfTheBook);
And then you can use one of the mutators (setters),
myBook.setOn_Loan (true);
Advantages:
unlike arrays, ArrayList is dynamic in size.
It is generic, you don't need to cast stuff.
And that is basically a guide to using array lists. Now you want to make a class that do all this stuff. So it must contain an ArrayList<Book>:
public class Library {
private ArrayList<Book> books
public Library () {
books = new ArrayList<> ();
}
public ArrayList<Book> getBooks () {
return books;
}
}
Then the user can get the books and do operations on the array list.
Alternatively, you can make it more abstract. You can add borrowBook, returnBook, editBook and other methods to the class. For example, the borrowBook method would be like this:
public void borrowBook (int bookIndex) {
Book book = books.get(bookIndex);
book.setOn_Loan (true);
}
first, you will have to create the Book object
then you can create an array of Book objects like this
Book[] books = new Book[10]; //fixed list of size 10
Book b1 = new Book(); // create a book object
books[0] = b1; // assign it to be the first array element
or an arraylist list like this
ArrayList<Book> books = new ArrayList<Book>(); //initial empty list, no fixed size
Book b1 = new Book(); // create a book object
books.add(b1); // append it to the list
If their is a variable number of books, using an ArrayList will be a good choice, as you can add more books on the fly, unlike an array, where you have to fix the size.
To create an ArrayList of Book objects, use: ArrayList<Book> books = new ArrayList<Book>();
To add a book to the list: books.add(new Book());
To perform a command on a book (i.e. edit the details), you need to know the index of the book, or you could go through all of them. You can do this using the .get(index) command, for example:
books.get(index).doSomething();
You can read more about ArrayLists and all of their methods here, and a simple tutorial could be found here.
I'm very new to java, and trying to grasp making an object with two different values.
I'm trying to create a Customer object called customer, with the initial values of 1 and cust1, and then display the customer object to the output with toString()
Thanks for any help in advance.
Here's what I have currently.
public class Customer {
private int id;
private String name;
public Customer(int id, String name) {
this.id = id;
this.name = name;
Customer customer = new Customer(1, "cust1");
}
You have no entry point to your program, which should look like this in your class
public static void main(String[] args)
{
//objects created here
}
You also create a Customer object as a member of your Customer class which means every Customer object contains another.
You can't set Customer members like this
Customer customer = new Customer(); //you also don't have a no argument constructor
customer = 1; //how would it know where to put this 1?
customer = cust1; //same as above
it would be like this (if they were in the right place, as mentioned above)
Customer customer = new Customer(); //if using this method you will need a no argument constructor
customer.id = 1;
customer.name = cust1;
or like this
new Customer(1,"cust1");
In Summary
You need an entry point
You are creating Customer with a no argument constructor but you only have one constructor which has two arguments
You are -for some reason- creating a Customer inside every Customer
You are not setting members of your Customer object in the correct (or even in a valid) way
Don't create a new object instance within a classes constructor — this will result in a StackoverFlowException.
public class Customer {
private final int id;
private final String name;
public Customer(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
In a separate class you can simply create a new instance by using
Customer customer = new Customer(1, "Name");