6
\$\begingroup\$

Can I improve my code? There are 3 types of hamburgers.

The basic hamburger will have these properties:

  • prices
  • type of bread
  • type of meat
  • maximum 4 supplements

Then, create a Bio burger that will be gray bread, and which can receive in addition 2 elements supplement to the basic either 6 supplements max.

After, create a Deluxe Hamburger : that will be provided with fries and a drink, but it will not be possible to add supplements.

Class Hamburger

public class Hamburger {

  // Attributes 

  double price; 
  private String typeBread;
  private String typeMeat;
  int counter; 


  public Hamburger(double price, String typeBread, String typeMeat)
  {
    this.price = price;
    this.typeBread = typeBread;
    this.typeMeat = typeMeat;
    this.counter = 0;

    System.out.println("Hamburger " + this.getTypeBread() + " - " + this.typeMeat + " - " + this.getPrice() + " euros");
  }

  // add supplement 4 maximum

  public void addSupplement(String type, double amount)
  {
    counter++;
    if(counter <= 4)
    {
      System.out.println("Supplement " + counter + " : " + type + " - " + amount + " euros");
      this.price = this.price + amount; 
    }
    else
    {
      System.out.println("Error supplement maximum is 4 ");
    }
  }

  public void total()
  {
    System.out.println("Total => " + this.getPrice() + " euros"); 
  }




  // les getters

  public double getPrice()
  {
    return price; 
  }

  public String getTypeBread()
  {
    return typeBread;
  }

  public String getTypeMeat()
  {
    return typeMeat;
  }

  public int getCounter()
  {
    return counter;
  }

}

Class Bio

public class Bio extends Hamburger  {

  public Bio(double price, String typeMeat) {
        super(price, "gray bread", typeMeat);

    }

    public void addSupplement(String type, double amount) {
        counter++;
        if (counter<=6){
            System.out.println("Supplement " + counter + " : " + type + " - " + amount + " euros ");
            this.price = this.price+ amount;
        }
        else{
            System.out.println("Error supplement 6 maximum ");
        }
    }   

}

Class Deluxe

public class Deluxe extends Hamburger {

   private String accompaniment;
   private String drink;


   // Builders


     public Deluxe () {
         super (7.99, "white bread", "veal");
         this.accompaniment = "fried";
         this.drink = "drink";

         System.out.println ("Included in the DELUXE formula:" + this.getDrink () + "-" + this.getAccompaniment ());
     }



     public String getAccompaniment () {
         return accompaniment;
     }

     public String getDrink () {
         return drink;
     }

     public void addSupplement (String type, double price) {
         System.out.println ("No supplement allowed for this formula");
     }

     public void total () {
         super.total ();
     }
}

Class Main

public class Main {

    public static void main(String[] args) {

    System.out.println("BASIC");
    Hamburger myHamburger = new Hamburger(5.99, "white bread", "beef");
    myHamburger.addSupplement("Tomatos", 0.99);
    myHamburger.addSupplement("Bacons", 0.59);
    myHamburger.addSupplement("Onions", 0.49);
    myHamburger.addSupplement("Ketchup", 0.29);
    System.out.println("__________");
    myHamburger.total();
    System.out.println("-----------------------");

    System.out.println("BIO");
    Bio myBio = new Bio (6.99, "Veal");
    myBio.addSupplement ("Onions", 0.49);
    myBio.addSupplement("Tomatoes", 0.99);
    myBio.addSupplement ("Bacon", 0.59);
    myBio.addSupplement ("Cucumbers", 0.49);
    myBio.addSupplement("Ketchup", 0.29);
    myBio.addSupplement ("Mayo", 0.29);
    myBio.addSupplement ("Cocktail", 0.29);
    System.out.println ( "__________");
    myBio.total ();
    System.out.println("-----------------------");

    System.out.println("DELUXE");
    Deluxe myDeluxe = new Deluxe();
    myDeluxe.addSupplement("Tomatoes", 0.99);
    System.out.println("__________");
    myDeluxe.total();



}
}
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Things that I would like to point out in your code:

Use of Strings

I see that you used Strings in defining the names of the parts for your burger like bread, and meat types. I suggest you use enums so as to regulate the possible types of bread, meat, and others that can be added to a meal, like so:

BreadType Enum

public enum BreadType {
    WHITE_BREAD("white bread");

    private String type;

    BreadType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return type;
    }
}

MeatType Enum

public enum MeatType {
    BEEF("beef"), VEAL("veal");

    private final String type;

    MeatType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return type;
    }
}

You can also use enums to store other properties too. This can be done for items like Supplements which have prices attached to them, drinks, and sides like so:

Supplement Enum

public enum Supplement implements FoodItem {
    TOMATOES("tomato", 0.99), BACON("bacon", 0.59), ONIONS("onion", 0.49),
    KETCHUP("ketchup", 0.29), COCKTAIL("cocktail", 0.29), CUCUMBERS("cucumbers", 0.29);

    private BigDecimal price;
    private String type;

    Supplement(String type, double price) {
        this.type = type;
        this.price = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_DOWN);
    }

    @Override
    public String toString() {
        return type;
    }

    public BigDecimal getPrice() {
        return price;
    }
}

Drink Enum

public enum Drink implements FoodItem{
    APPLE_JUICE("apple juice", 3.49);

    private final BigDecimal price;
    private final String name;

    Drink(String name, double price) {
        this.name = name;
        this.price = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_DOWN);
    }

    public BigDecimal getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return name;
    }
}

Side Enum

public enum Side implements FoodItem {
    FRIES("fries", 3.99);

    private final BigDecimal price;
    private final String name;

    Side(String name, double price) {
        this.name = name;
        this.price = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_DOWN);
    }

    public BigDecimal getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return name;
    }
}

You may have noticed the use of BigDecimals in prices part instead of double. The reason for this is that BigDecimal gives us a way to exactly represent numbers. More on this reason over here.

The Hamburger Meals

I take it you want to create different hamburger meals -- each meal having different items compared to that of the other meals. Here's what I did:

FoodItem interface

public interface FoodItem {
    BigDecimal getPrice();
}

You mentioned four "food items" in the problem: Hamburger, Fries, Supplement, and Drink. Assuming that each "food item" has a price, these classes should implement FoodItem. The reason for this is to ease the computation of the price in a hamburger meal. Speaking of hamburger meal, I also created a HamburgerMeal class:

HamburgerMeal class

public class HamburgerMeal {
    private final List<FoodItem> foodItems;
    private final List<Supplement> supplements;
    private final HamburgerMealType hamburgerMealType;

    public HamburgerMeal(HamburgerMealType hamburgerMealType) {
        this.foodItems = new ArrayList<FoodItem>();
        this.supplements = new ArrayList<Supplement>();
        this.hamburgerMealType = hamburgerMealType;
    }

    public BigDecimal getPrice(){
        BigDecimal resultingPrice = BigDecimal.ZERO;
        for(FoodItem foodItem : foodItems){
            resultingPrice = resultingPrice.add(foodItem.getPrice());
        }
        for(Supplement supplement : supplements){
            resultingPrice = resultingPrice.add(supplement.getPrice());
        }
        return resultingPrice;
    }

    public void addItem(FoodItem foodItem){
        foodItems.add(foodItem);
    }

    public void addSupplement(Supplement supplement) {
        checkIfAddingSupplementsIsStillAllowed();
        supplements.add(supplement);
    }

    private void checkIfAddingSupplementsIsStillAllowed() {
        if(supplements.size() == hamburgerMealType.getMaxNumberOfSupplements())
            throw new AdditionOfItemNotAllowedException("No more supplements can be added to " + hamburgerMealType);
    }

    @Override
    public String toString() {
        return hamburgerMealType + " burger meal";
    }
}

You may have noticed the variable HamburgerMealType having a property called maxNumberOfSupplements. That's because, it's also an Enum!

HamburgerMealType Enum

public enum HamburgerMealType {
    BASIC("basic", 4), BIO("bio", 6), DELUXE("deluxe", 0);

    private final String name;
    private final int maxNumberOfSupplements;

    HamburgerMealType(String name, int maxNumberOfSupplements) {
        this.name = name;
        this.maxNumberOfSupplements = maxNumberOfSupplements;
    }

    @Override
    public String toString() {
        return name;
    }

    public int getMaxNumberOfSupplements() {
        return maxNumberOfSupplements;
    }
}

This helps us keep track the main property of a MealType which is the maximum number of Supplements it can have.

You may have also noticed the use of AdditionOfItemNotAllowedException. Whenever you think something "illegal" can happen (which is adding a supplement into a meal that can't have supplements), it is best to catch them with Exceptions instead of just saying that it's "illegal". Here's the code for the said exception:

public class AdditionOfItemNotAllowedException extends IllegalArgumentException {
    public AdditionOfItemNotAllowedException(String message) {
        super(message);
    }
}

Lastly, we have the Hamburger class.

Hamburger class

public class Hamburger implements FoodItem {
    private final BigDecimal price;
    private final BreadType breadType;
    private final MeatType meatType;

    private Hamburger(Builder builder){
        this.price = builder.price;
        this.breadType = builder.breadType;
        this.meatType = builder.meatType;
    }

    public static class Builder{
        private final BigDecimal price;

        private BreadType breadType = BreadType.WHITE_BREAD;
        private MeatType meatType = MeatType.BEEF;

        public Builder(double price){
            this.price = new BigDecimal(price).setScale(2, BigDecimal.ROUND_HALF_DOWN);
        }

        public Builder breadType(BreadType breadType){
            this.breadType = breadType;
            return this;
        }

        public Builder meatType(MeatType meatType){
            this.meatType = meatType;
            return this;
        }

        public Hamburger build(){
            return new Hamburger(this);
        }
    }

    public BigDecimal getPrice(){
        return price;
    }

    public BreadType getBreadType() {
        return breadType;
    }

    public MeatType getMeatType() {
        return meatType;
    }
}

I used the static builder pattern for this one since the Hamburger specs you mentioned have defaults for BreadType and MeatType. This is also to avoid passing three parameters into the constructor which may get confusing when you don't know which parameter comes first.

I end this answer with the main code I wrote:

Main class

public class Main {
    public static void main(String[] args){
        HamburgerMeal standardBurgerMeal = new HamburgerMeal(HamburgerMealType.BASIC);
        Hamburger hamburger = new Hamburger.Builder(5.99).build();
        standardBurgerMeal.addItem(hamburger);
        standardBurgerMeal.addSupplement(Supplement.TOMATOES);
        standardBurgerMeal.addSupplement(Supplement.BACON);
        standardBurgerMeal.addSupplement(Supplement.ONIONS);
        standardBurgerMeal.addSupplement(Supplement.KETCHUP);
        System.out.println(standardBurgerMeal + " price: " + standardBurgerMeal.getPrice());

        HamburgerMeal bioBurgerMeal = new HamburgerMeal(HamburgerMealType.BIO);
        Hamburger bioBurger = new Hamburger.Builder(6.99).meatType(MeatType.VEAL).build();
        bioBurgerMeal.addItem(bioBurger);
        bioBurgerMeal.addSupplement(Supplement.TOMATOES);
        bioBurgerMeal.addSupplement(Supplement.BACON);
        bioBurgerMeal.addSupplement(Supplement.ONIONS);
        bioBurgerMeal.addSupplement(Supplement.KETCHUP);
        bioBurgerMeal.addSupplement(Supplement.COCKTAIL);
        bioBurgerMeal.addSupplement(Supplement.CUCUMBERS);
        System.out.println(bioBurgerMeal + " price: " + bioBurgerMeal.getPrice());

        HamburgerMeal deluxeBurgerMeal = new HamburgerMeal(HamburgerMealType.DELUXE);
        Hamburger deluxeBurger = new Hamburger.Builder(7.99).build();
        deluxeBurgerMeal.addItem(deluxeBurger);
        deluxeBurgerMeal.addItem(Drink.APPLE_JUICE);
        deluxeBurgerMeal.addItem(Side.FRIES);
        System.out.println(deluxeBurgerMeal + " price: " + deluxeBurgerMeal.getPrice());
    }
}

I apologize if my explanation is confusing. This is pretty much the first long answer I posted ever lol.

\$\endgroup\$
1
\$\begingroup\$

You should consider to generalize the addSupplement method. Imagine something like:

protected int maxSupplementCount = 4;

public void addSupplement(String type, double amount) {
    if(maxSupplementCount > 0) {
        System.out.println("Supplement " + counter + " : " +
            type + " - " + amount + " euros");
        maxSupplementCount--;
        this.price = this.price + amount;
    } else {
        System.out.println("Error supplement maximum reached.");
    }
}

The constructor for Bio for example would get an additional line.

public Bio(double price, String typeMeat) {
    super(price, "gray bread", typeMeat);
    this.maxSupplementCount = 6;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.