I have two classes one is called Modifiers and the other is called Options. Modifiers has an id, name and a group of options associated with it. While Options (or each option) has a name and price. Each option is associated with only one Modifier. What is the best way of Writing these classes to take into account their relationship. In my application, the user has to enter the name of the Modifier, then they have to enter the name and price of each option. Each modifier can have as many options as necessary. Here are the classes and how I am using them for now:the user has to enter the name of the Modifier, then they have to enter the name and price of each option. Each modifier can have as many options as necessary. Here are the classes and how I am using them for now:
public class Modifier {
int id;
String name;
Options [] options;
public Modifier() {
}
public Modifier(String name, Options[] options) {
this.name = name;
this.options = options;
}
public Modifier(int id, String name, Options[] options) {
this.id = id;
this.name = name;
this.options = options;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Options[] getOptions() {
return options;
}
public void setOptions(Options[] options) {
this.options = options;
}
}
I am currently add the group of Options as an array. Here is the Options class.
public class Options {
int id;
String name;
public Options() {
}
public Options(String name, long price) {
this.name = name;
this.price = price;
}
public Options(int id, String name, long price) {
this.id = id;
this.name = name;
this.price = price;
}
long price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
}
And in my main:
Options sausage = new Options("sausage",23);
Options olives = new Options("olives", 24);
Options bacon = new Options("bacon", 25);
Options [] toppings = {sausage, olives, bacon};
Modifier pizza_toppings = new Modifier(1, "Pizza toppings",toppings);
I plan on using an SQLIte DB so I need to find an efficient way of doing this.
you could add one field to Options class which save modifier id, then with sqlite you will create two tables one for modifiers and one for options, and when you retrieve data from it, you use foreign key to build your object. whoever your classes now looks fine, you may just save modifiers ids in options table and the vice versa like this:
modifier table [modifierId, name] - option table [optionId, name, modifierId]
Related
I am writing a simple inventory system for practice and I have an item class that holds these values:
private String name;
private int quantity;
private Integer ID;
private Double pricePerUnit;
private Double totalPrice;
I am writing the constructors for this class and I want everything except the name and quantity to be optional, as in the user can opt whether or not to input any data for those fields. Currently I have two constructors that look like this:
public Item(String name, int quantity)
{
this.name=name;
this.quantity=quantity;
}
public Item(String name, int quantity, Integer ID, Double pricePerUnit, Double totalPrice)
{
this(name, quantity);
this.ID=ID;
this.pricePerUnit=pricePerUnit;
this.totalPrice=totalPrice;
}
Is there any way I can make some of the arguments in the second constructor optional, or non-mandatory?
Thanks!
Naturally, in such cases I'd would think of two possibilities to get what you need, Constructor Overloading and Builder Pattern
Although when you have the same data formats, You can't naturally depend on the former. In such cases (as OP's Question) the best alternative is to go for a builder design pattern.
You can build an instance of Item.class as the following
public class Item {
\\... other public functions.. etc
static class ItemBuilder{
private Item item;
public ItemBuilder withNameAndQuantity(String name, int quantity){
item = new Item(); //default constructor or as per your usecase a private constructor
item.setName(name);
item.setQuantity(quantity);
return this;
}
public ItemBuilder withPricePerUnit(Double pricePerUnit){
if(item!=null){
item.setPriceUnit(pricePerUnit);
}
return this;
}
public ItemBuilder withTotalPrice(Double totalPrice){
if(item!=null){
item.setTotalPrice(totalPrice);
}
return this;
}
public Item build(){
if(item!=null){
return item;
}else{
throw new IllegalStateException("item is null, no name or id set");
}
}
}
}
Finally, you could build a new Item by doing the following :
Item item = new Item.ItemBuilder(). withNameAndQuantity("apple",10). withTotalPrice(100).build();
Ideally you would decompose the class into coherent pieces, in much the same way as you might normalise a database schema.
There is the Builder Pattern.
You code could be written better by making the constructor will all the attributes the "canonical constructor* and forward to that. This will also make it easier to switch over to records when they become available.
public Item(String name, int quantity) {
this(name, quantity, null, null, null);
}
public Item(String name, int quantity, Integer id, Double pricePerUnit, Double totalPrice) {
this.name = name;
this.quantity = quantity;
this.ID = ID;
this.pricePerUnit = pricePerUnit;
this.totalPrice = totalPrice; // Shouldn't this be calculated?
}
(Not that nulls are ideal.)
One way is to create more constructors and another is to loose the immutability and introduce setter methods.
Hence, you can use Builder Pattern as Builder Pattern will help you to consume additional attributes while retaining the immutability of Item class.
Below is the coded solution. This uses a additional class ItemBuilder which helps us in building desired Item object with all mandatory attributes and combination of optional attributes, without loosing the immutability.
public class Item {
//All final attributes
private String name; // required
private int quantity; // required
private Integer ID; // optional
private Double pricePerUnit; // optional
private Double totalPrice; // optional
private Item(ItemBuilder builder) {
this.name = builder.name;
this.quantity = builder.quantity;
this.ID = builder.ID;
this.pricePerUnit = builder.pricePerUnit;
this.totalPrice = builder.totalPrice;
}
//All getter, and NO setter to provide immutability
public String getName() {
return name;
}
public int getQuantity() {
return quantity;
}
public Integer getID() {
return ID;
}
public Double getPricePerUnit() {
return pricePerUnit;
}
public Double getTotalPrice() {
return totalPrice;
}
#Override
public String toString() {
return "User: "+this.name+", "+this.quantity+", "+this.ID+", "+this.pricePerUnit+", "+this.totalPrice;
}
public static class ItemBuilder
{
private String name; // required
private int quantity; // required
private Integer ID; // optional
private Double pricePerUnit; // optional
private Double totalPrice; // optional
public ItemBuilder(String name, int quantity) {
this.name = name;
this.quantity = quantity;
}
public ItemBuilder ID(Integer ID) {
this.ID = ID;
return this;
}
public ItemBuilder pricePerUnit(Double pricePerUnit) {
this.pricePerUnit = pricePerUnit;
return this;
}
public ItemBuilder totalPrice(Double totalPrice) {
this.totalPrice = totalPrice;
return this;
}
//Return the finally constructed Item object
public Item build() {
Item item = new Item(this);
validateUserObject(item);
return item;
}
private void validateUserObject(Item item) {
//Do some basic validations to check
//if item object does not break any assumption of system
}
}
}
OR
You can also make use of JsonProperties.
#JsonIgnoreProperties(ignoreUnknown = true)
public record Item(
String name,
Integer quantity,
#JsonInclude(JsonInclude.Include.NON_NULL) Integer ID,
#JsonInclude(JsonInclude.Include.NON_NULL) Double pricePerUnit,
#JsonInclude(JsonInclude.Include.NON_NULL) Double totalPrice) {}
I hope this gives you clarity on how to resolve your problem.
I have a two different list and using those i have prepare third list using streams.
Student.java
public class Student {
int id;
String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
StudentLoc.java
public class StudentLoc {
int id;
String loc;
public StudentLoc(int id, String loc) {
super();
this.id = id;
this.loc = loc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
}
and I have third class like below.
StudentDetLoc.java
public class StudentDetLoc {
int id;
String name;
String Loc;
}
I have to compare the Student list and StudentLoc list by using id property.
if id present in both list then i have to prepare StudentDetLoc list using both lists.
My approach would be:
Make set of student ids from first list using streams() and map()
Filter filter() second list using set obtained from step 1
Use forEach() as terminating operation of step 2 and append to final 3rd list (keeping only id, name and Loc).
I want to create objects with a name and a unique ID number that increments with the creation of each user.
class user {
static int uid = 0;
String name;
public user (String name){
User.uid = uid++;
this.name = name;
}
}
When creating user objects in a main method and printing out their ID they all return 0. I think there is a simply fix to this but can't seem to find it elsewhere online.
Your code has several problems:
A User doesn't have any ID. All you have is a static ID, thus shared by all users
You're incrementing the static ID, and then assigning its previous value to the ID right after.
You're not respecting the Java naming conventions.
The code should be
class User {
private static int uid = 0;
private String name;
private int id;
public User(String name) {
uid++;
this.id = uid;
this.name = name;
}
// getters
}
or, if you want the IDs to start at 0:
class User {
private static int uid = 0;
private String name;
private int id;
public User(String name) {
this.id = uid++;
this.name = name;
}
// getters
}
I am using JPA and wanted to figure out how the many-to-many relationship. Let's say I have a "Store" and a "Customer". These have a many to many relationship.
So my understanding is, a Store can have many Customers, and Customer can be associated with many Stores. So what I wanted to do is create two Stores and several customers. Then I wanted to have the same customer be a part of Store 1 and Store 2. However, when I saved Store 1 with the customer, and then took that same customer and associated it with Store 2 (let's say the customers shops at both stores), I get this error message: detached entity passed to persist.
Not sure how to resolve this. Any help and comments are appreciated. Thanks in advance!
#Entity
public class Store {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
private List<Item> items = new ArrayList<>();
#ManyToMany(cascade=CascadeType.ALL)
private List<Customer> customers = new ArrayList<>();
public List<Customer> getCustomers() {
return customers;
}
public void setCustomers(List<Customer> customers) {
this.customers = customers;
}
public Store() {
}
public Store(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public Store addItem(Item item) {
items.add(item);
return this;
}
}
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private BigDecimal price;
public Item() { }
public Item(String name, BigDecimal price) {
this.name = name;
this.price = price;
}
public Item() {
}
public Item(String name, BigDecimal price) {
this.name = name;
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
This is the driver code using Spring Boot:
Store safeway = new Store("Safeway4");
safeway.addItem(new Item("Fuji Apple", new BigDecimal(1)));
safeway.addItem(new Item("Black Grapes", new BigDecimal(2)));
safeway.addItem(new Item("Cheese Pizza", new BigDecimal(10)));
Store bestBuy = new Store("Best Buy4");
bestBuy.addItem(new Item("55 inch TV", new BigDecimal(550)));
bestBuy.addItem(new Item("Bluray Player", new BigDecimal(85)));
bestBuy.addItem(new Item("Nikon SLR", new BigDecimal(1500)));
Customer elf = new Customer();
elf.setName("Elf");
Customer neo = new Customer();
neo.setName("Neo");
safeway.getCustomers().add(elf);
safeway.getCustomers().add(neo);
Customer yoda = new Customer();
yoda.setName("Yoda");
Customer crazy = new Customer();
crazy.setName("Crazy");
bestBuy.getCustomers().add(yoda);
bestBuy.getCustomers().add(crazy);
log.debug("adding neo to best buy");
bestBuy.getCustomers().add(neo); // Adding Neo to both stores!
log.debug("saving safeway 1");
storeRepository.save(safeway);
log.debug("saving safeway 1 done");
log.debug("saving bestBuy 1");
storeRepository.save(bestBuy); // error happens here <-----------
log.debug("saving bestBuy 1 done");
If you remove the CascadeType.ALL, you'll avoid this problem.
Logically, a Customer can exist without ever being associated to any Store. That means the lifecycle of a Customer should be independent of that of a Store entity, thus cascading any operation for a Customer from Store is wrong.
You save your Customer instances separately, associate the saved instances with the appropriate Store and then save it separately.
I'm writing my new java project and a requirement is to represent product that can belong to a category.
I'm using a database in my project and I connect products and categories by a foreign key.
In the code, instead, I've to use SOLID design and I don't understand how can I connect products and categories.
In a first version, the code was
public class Product {
private int ID;
private String name;
private String descr;
private int stock;
private float price;
private int category;
public Product(int anID, String aName, String aDescr, int aStock, float aPrice, int aCategory) {
this.ID = anID;
this.name = aName;
this.descr = aDescr;
this.stock = aStock;
this.price = aPrice;
this.category = aCategory;
}
public int getID() { return this.ID; }
public String getName() { return this.name; }
public String getDescr() { return this.descr; }
public int getStock() { return this.stock; }
public float getPrice() { return this.price; }
public int getCategory() { return this.category; }
public void decreaseStock(int x) { this.stock -= x; }
}
and
public class Category {
private int ID;
private String name;
private String descr;
public Category (int anID, String aName, String aDescr) {
this.ID = anID;
this.name = aName;
this.descr = aDescr;
}
public int getID() { return this.ID; }
public String getName() { return this.name; }
public String getDescr() { return this.descr; }
}
... but I'm thinking that product can implements category, in order to have all information in one object and not jump between two classes...
Which is the best way to write it?
You should not mimic the underlying database table structure in your Java classes verbatim. The correct way to do and which every ORM approach that I worked on until now uses is as follows:
Product class stores a reference to a Category instance.
When fetching the records from a database within the data access layer you would explicitly write code to to create a Category object first and then pass it to the Product class constructor when creating the Product object.
This way the Java class hierarchy reflects the true business relationship between a Product and its related Category. This also has the advantage of abstracting the storage details from the application - consider what would happen with the approach you are currently adopting if the data were to be stored in a NoSQL database. However, by adopting the approach presented in this answer you would only need to change the Data access layers for creating the correct objects - your class design remains intact (The O of Open-Closed principle in SOLID).