MHB UML class diagram for a system.

Click For Summary
A UML class diagram for a hotel billing system should include a Customer class with subclasses for Corporate, Group, and Individual customers, but the hierarchy should focus on shared attributes and behaviors rather than distinct functionalities. The system must automate billing by storing customer details and calculating charges based on a flat rate, with discounts for corporate and group bookings. A HotelBillingSystem class should manage bookings and compute bills, while a Discount class can handle various discount types, allowing for flexibility in pricing strategies. Each customer instance can have associated discounts or extra charges, which simplifies billing without needing to identify customer types at runtime. This design promotes a clean, extensible architecture for managing hotel billing.
  • #31
Bacterius said:
Hum. The HotelBooking class in your diagram has a line connecting it to the customer, so I was under the impression every hotel booking was associated with a customer (like it's associated with a room). If that was not the case and I misread, then yes you might have to invert the logic a little bit (for instance if instead of bookings holding customers you have customers holding bookings, then instead of booking.getCustomer() you'd want customer.getBooking() and so forth). Either way the diagram is indeed missing something since you have a relationship between Customer and HotelBooking yet neither have methods that interact with the other (i.e. in the calculateBill() method, how is the billing system to know which customer is associated with a given hotel booking? that is the problem you are having right now)

Sorry for the confusion, does that clear things up a bit?


Ah, I see. Ideally I'd like to follow my UML and connect it so that every hotel booking is connected with a customer.

I've looked back at my UML, which is slightly different from the last time I uploaded it, and can see that a the Customer class is associated to HotelBooking class with aggregation.

I've done some reading to find out how aggregation is implemented in Java and found this.

Code:
final class Car {

  private Engine engine;

  void setEngine(Engine engine) {
    this.engine = engine;
  }

  void move() {
    if (engine != null)
      engine.work();
  }
}

I've played around and can't seem to it so this line works though.

Code:
Discount discount = booking.getCustomer().getDiscount();

Any tips would be fantastic! :D
 
Technology news on Phys.org
  • #32
JaAnTr said:
Ah, I see. Ideally I'd like to follow my UML and connect it so that every hotel booking is connected with a customer.

I've looked back at my UML, which is slightly different from the last time I uploaded it, and can see that a the Customer class is associated to HotelBooking class with aggregation.

I've done some reading to find out how aggregation is implemented in Java and found this.

Code:
final class Car {

  private Engine engine;

  void setEngine(Engine engine) {
    this.engine = engine;
  }

  void move() {
    if (engine != null)
      engine.work();
  }
}

I've played around and can't seem to it so this line works though.

Code:
Discount discount = booking.getCustomer().getDiscount();

Any tips would be fantastic! :D

Can you show your latest UML diagram?

If you are going with "booking has a customer" then I'd simply pass the Customer to the booking's constructor (which connects the customer to the booking) and then add a getCustomer() method to the booking to retrieve it. Because here the HotelBooking doesn't have any functionality by itself (which is all in the HotelBookingSystem), it merely stores the customer that should be billed for the booking.
 
  • #33
Bacterius said:
Can you show your latest UML diagram?

If you are going with "booking has a customer" then I'd simply pass the Customer to the booking's constructor (which connects the customer to the booking) and then add a getCustomer() method to the booking to retrieve it. Because here the HotelBooking doesn't have any functionality by itself (which is all in the HotelBookingSystem), it merely stores the customer that should be billed for the booking.

View attachment 4039

So then the HotelBooking constructor should look this this?

Code:
	public HotelBooking(String dateFrom, String dateTo, Customer customer) throws ParseException{
		this.dateFrom = new SimpleDateFormat( "yyyy MM dd" ).parse(dateFrom);
		this.dateTo = new SimpleDateFormat( "yyyy MM dd" ).parse(dateTo);
		this.customer = customer;
	}

And then the HotelBooking also has a method called getCustomer(), but what is that returning? I assume it should essentially return what type of customer it is, so either individual, group or corporate but how do I go about doing that?
 

Attachments

  • UML.png
    UML.png
    24.4 KB · Views: 115
  • #34
JaAnTr said:
So then the HotelBooking constructor should look this this?

Code:
	public HotelBooking(String dateFrom, String dateTo, Customer customer) throws ParseException{
		this.dateFrom = new SimpleDateFormat( "yyyy MM dd" ).parse(dateFrom);
		this.dateTo = new SimpleDateFormat( "yyyy MM dd" ).parse(dateTo);
		this.customer = customer;
	}

And then the HotelBooking also has a method called getCustomer(), but what is that returning? I assume it should essentially return what type of customer it is, so either individual, group or corporate but how do I go about doing that?

The constructor is correct. The getCustomer() method just returns this.customer as a Customer object, without any further work necessary: you don't need to differentiate between individual/group/corporate customers because all the differentiation is already done in the discount/charge objects you implemented.
 
  • #35
Bacterius said:
The constructor is correct. The getCustomer() method just returns this.customer as a Customer object, without any further work necessary: you don't need to differentiate between individual/group/corporate customers because all the differentiation is already done in the discount/charge objects you implemented.

Ok, I've got the first line giving me no errors but the second one still is:

Code:
	        Customer customer = booking.getCustomer();
	        Discount discount = customer.getDiscount();

I can see on my UML diagram that the Discount class is connected to the Customer class by aggregation. So does this mean that the Discount class needs a Customer passed to it in it's constructor and then a getDiscount method or is it the other way around? Because the Discount class is just an interface that looks like this and I know interfaces can't have constructors so how do I connect it to the customer?

Code:
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;public interface Discount {

	public BigDecimal getDiscount(Date date);
	
}
 
  • #36
JaAnTr said:
Ok, I've got the first line giving me no errors but the second one still is:

Code:
	        Customer customer = booking.getCustomer();
	        Discount discount = customer.getDiscount();

I can see on my UML diagram that the Discount class is connected to the Customer class by aggregation. So does this mean that the Discount class needs a Customer passed to it in it's constructor and then a getDiscount method or is it the other way around? Because the Discount class is just an interface that looks like this and I know interfaces can't have constructors so how do I connect it to the customer?

Code:
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;public interface Discount {

	public BigDecimal getDiscount(Date date);
	
}

You are right that the Discount is an interface. However, the classes derived from Discount (such as CorporateDiscount) are not, so these are the ones you attach to the Customer. If the customer has no discount, then it just stays null, otherwise [say, in the CorporateCustomer's constructor] you can create a CorporateDiscount and assign it to that customer's discount field (so that getDiscount() returns that).

(you can assign a CorporateDiscount to a Discount because a CorporateDiscount "is" a Discount, i.e. it inherits from it - this is what allows polymorphism)
 
  • #37
Bacterius said:
You are right that the Discount is an interface. However, the classes derived from Discount (such as CorporateDiscount) are not, so these are the ones you attach to the Customer. If the customer has no discount, then it just stays null, otherwise [say, in the CorporateCustomer's constructor] you can create a CorporateDiscount and assign it to that customer's discount field (so that getDiscount() returns that).

(you can assign a CorporateDiscount to a Discount because a CorporateDiscount "is" a Discount, i.e. it inherits from it - this is what allows polymorphism)

I'm slightly confused what, for example, the CorporateDiscount class should look like then? I've added a constructor that takes a customer but don't know what you mean when you say "create a CorporateDiscount and assign it to that customer's discount field (so that getDiscount() returns that)."

This is my CorporateDiscount class currently:

Code:
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;

public class CorporateDiscount implements Discount {

	Customer customer;
	
	public CorporateDiscount(Customer customer){
		this.customer = customer;
	}
	
    @Override
    public BigDecimal getDiscount(Date date) {
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
    	if ((Calendar.SATURDAY == cal.get(Calendar.DAY_OF_WEEK)) || (Calendar.SUNDAY == cal.get(Calendar.DAY_OF_WEEK))) {
    		BigDecimal weekend = new BigDecimal(0.5);
            return weekend;
        } else {
        	BigDecimal weekday = new BigDecimal(0.8);
            return weekday;
        }
    }

}
 
  • #38
Something like this (EDITED):

Code:
public class CorporateCustomer implements Customer {
    private CorporateDiscount discount;

    // ...

    public CorporateCustomer(String name, String address, etc..) {
        discount = new CorporateDiscount();
        this.name = name;
        // etc..
    }

    public Discount getDiscount() {
        return discount;
    }

    // etc..
}

And then the CorporateDiscount has no knowledge of the customer class and takes no customer in its constructor (it's the opposite: the customer knows about the type of discount it is entitled to).
 
  • #39
Bacterius said:
Something like this (EDITED):

Code:
public class CorporateCustomer implements Customer {
    private CorporateDiscount discount;

    // ...

    public CorporateCustomer(String name, String address, etc..) {
        discount = new CorporateDiscount();
        this.name = name;
        // etc..
    }

    public Discount getDiscount() {
        return discount;
    }

    // etc..
}

And then the CorporateDiscount has no knowledge of the customer class and takes no customer in its constructor (it's the opposite: the customer knows about the type of discount it is entitled to).
I've changed my CorporateDiscount class to reflect your suggestions:

Code:
import java.text.ParseException;public class CorporateCustomer implements Customer {

	String name;
	Integer phone;
	String address;
	private CorporateDiscount discount;
	HotelBooking hotelBooking;

	public CorporateCustomer(String name, int phone, String address, String dateTo, String dateFrom) throws ParseException{
		this.name = name;
		this.phone = phone;
		this.address = address;
		this.hotelBooking = new HotelBooking(dateTo, dateFrom, null);
		
	}
	
	
	@Override
	public void setName(String newName) {
		name = newName;
	}

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

	@Override
	public void setPhone(Integer newPhone) {
		phone = newPhone;
	}

	@Override
	public Integer getPhone() {
		return phone;
	}

	@Override
	public void setAddress(String newAddress) {
		address = newAddress;
	}

	@Override
	public String getAddress() {
		return address;
	}
	
	public Discount getDiscount() {
	    return discount;
	}

}

But I'm still getting an error on this line in HotelBooking:

Code:
Discount discount = customer.getDiscount();

With the error "The method getDiscount() is undefined for the type Customer".
 
  • #40
You probably haven't added the getDiscount() method to the Customer interface.
 
  • #41
Bacterius said:
You probably haven't added the getDiscount() method to the Customer interface.

Got it working (with slight issues, haha)! :D

Basically I've got it working for a CorporateCustomer now, however no discount is being applied to him at all. I've been looking and tinkering but I just can't get a discount to be taken off.

I'll post the relevant code if you don't mind having a look, I'm sure it's reasonably obvious but I can't see it. I've had to do some conversion between Calendars and Dates but aside from that not changed it much.

I know that I haven't used the HotelBillingSystem class to calculate it, but I'm just testing it at the moment.

CorporateCustomer
Code:
import java.text.ParseException;public class CorporateCustomer implements Customer {

	String name;
	Integer phone;
	String address;
	private CorporateDiscount discount;	public CorporateCustomer(String name, int phone, String address, String dateTo, String dateFrom) throws ParseException{
		this.name = name;
		this.phone = phone;
		this.address = address;
	}
	
	
	@Override
	public void setName(String newName) {
		name = newName;
	}

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

	@Override
	public void setPhone(Integer newPhone) {
		phone = newPhone;
	}

	@Override
	public Integer getPhone() {
		return phone;
	}

	@Override
	public void setAddress(String newAddress) {
		address = newAddress;
	}

	@Override
	public String getAddress() {
		return address;
	}
	
	public Discount getDiscount() {
	    return discount;
	}

}

CorporateDiscount
Code:
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;

public class CorporateDiscount implements Discount {

	Customer customer;
	
	public CorporateDiscount(Customer customer){
		this.customer = customer;
	}
	
    @Override
    public BigDecimal getDiscount(Date date) {
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
    	if ((Calendar.SATURDAY == cal.get(Calendar.DAY_OF_WEEK)) || (Calendar.SUNDAY == cal.get(Calendar.DAY_OF_WEEK))) {
    		BigDecimal weekend = new BigDecimal(0.5);
            return weekend;
        } else {
        	BigDecimal weekday = new BigDecimal(0.8);
            return weekday;
        }
    }

}

HotelBooking
Code:
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Currency;
import java.util.Date;
import java.util.concurrent.TimeUnit;public class HotelBooking {
	
	Date dateFrom;
	Date dateTo;
	long stayLength;
	long weekends;
	private Integer flatRate = 100;
	private BigDecimal totalBill;
	Customer customer;	public HotelBooking(String dateFrom, String dateTo, Customer customer) throws ParseException{
		this.dateFrom = new SimpleDateFormat( "yyyy MM dd" ).parse(dateFrom);
		this.dateTo = new SimpleDateFormat( "yyyy MM dd" ).parse(dateTo);
		this.customer = customer;
	}
	
	public void setDateFrom(String newDate) throws ParseException{
		dateFrom = new SimpleDateFormat( "yyyy MM dd" ).parse(newDate);
	}
	
	public Date getDateFrom(){
		return dateFrom;
	}
	
	public void setDateTo(String newDate) throws ParseException{
		dateTo = new SimpleDateFormat( "yyyy MM dd" ).parse(newDate);
	}
	
	public Date getDateTo(){
		return dateTo;
	}
	
	public long calculateStayLength(){
		long diff = dateTo.getTime() - dateFrom.getTime();
	    stayLength = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
	    return stayLength;
	}
	
	public Customer getCustomer(){
		return this.customer;
	}
	
	public BigDecimal calculateBill(HotelBooking booking) {
	    Calendar cal1 = Calendar.getInstance();
	    Calendar cal2 = Calendar.getInstance();
	    cal1.setTime(booking.getDateFrom());
	    cal2.setTime(booking.getDateTo());

	    BigDecimal totalBill =  new BigDecimal(0.0);
	    while (cal1.before(cal2)) {
	        // for each day of the stay for this booking... (here day = cal1)
	    	Date dateCal1 = cal1.getTime();
	        BigDecimal billForThisDay = new BigDecimal(flatRate);

	        // work out the discount...
	        Customer customer = booking.getCustomer();
	        Discount discount = customer.getDiscount();
	        
	        //Discount discount = booking.getCustomer().getDiscount();

	        if (discount != null) { // has discount?
	            // what is the discount for this day?
	        	System.out.println(discount.getDiscount(dateCal1));
	            billForThisDay = billForThisDay.multiply(discount.getDiscount(dateCal1));
	        }

	        // same thing for extra charge and anything else needed to bill...

	        totalBill = totalBill.add(billForThisDay);

	        cal1.add(Calendar.DATE,1); // go to the next day
	}
	    System.out.println(totalBill);
	    return totalBill;
	}
	
}

Main
Code:
import java.text.ParseException;public class Main {

	public static void main(String[] args) throws ParseException {
		CorporateCustomer myCorporateCustomer = new CorporateCustomer("James", 01633, "5 King Edward Road", "2015 02 19", "2015 02 27");		
		HotelBooking hb = new HotelBooking("2015 02 19", "2015 02 26" , myCorporateCustomer);
		hb.calculateBill(hb);

	}

}

Cheers :DEDIT:

Done some more debugging, and it turns out that this loop,

Code:
	        if (discount != null) { // has discount?
	            // what is the discount for this day?
	        	System.out.println("TEST TO SEE IF THIS GETS EXECUTED");
	        	System.out.println(discount.getDiscount(dateCal1));
	            billForThisDay = billForThisDay.multiply(discount.getDiscount(dateCal1));
	        }

never gets executed, so discount must be null. Why is this?
 
Last edited:
  • #42
The discount is null because you never created the discount (assigned an actual CorporateDiscount to the customer's discount field) in the CorporateCustomer's constructor. :)
 
  • #43
Bacterius said:
The discount is null because you never created the discount (assigned an actual CorporateDiscount to the customer's discount field) in the CorporateCustomer's constructor. :)

Oh of course, thought it was because a discount was never made. This might be stupid but the CorporateDiscount class takes a customer as a parameter, so when I'm creating it the CorporateCustomer's constructor what do I put as the parameter since shouldn't it be the CorporateCustomer itself, if that makes sense.

Code:
CorporateDiscount discount = new CorporateDiscount(What goes in here?);
 
  • #44
JaAnTr said:
Oh of course, thought it was because a discount was never made. This might be stupid but the CorporateDiscount class takes a customer as a parameter, so when I'm creating it the CorporateCustomer's constructor what do I put as the parameter since shouldn't it be the CorporateCustomer itself, if that makes sense.

Code:
CorporateDiscount discount = new CorporateDiscount(What goes in here?);

Technically it can (it's the famous "this" keyword) but if you look closely at your CorporateDiscount class you will find it doesn't actually need the customer anyway :D
 
  • #45
Bacterius said:
Technically it can (it's the famous "this" keyword) but if you look closely at your CorporateDiscount class you will find it doesn't actually need the customer anyway :D

Perfect! It's working now, just got to do the other types of customers but that should be straight forward, hopefully won't have any more issues. Thanks! :D
 
  • #46
Ok, I've finished doing the other customer types and it's all working. Just going back through the spec and I read this.

"The main focus of your implementation should concentrate upon manipulating a list (or array/vector) of customers."

I'm not sure exactly what this means, but this is what I've done in my main class.

Code:
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;public class Main {

	public static void main(String[] args) throws ParseException {
		
		HotelBillingSystem hbs = new HotelBillingSystem();
		
		CorporateCustomer myCorporateCustomer = new CorporateCustomer("James", 01633, "5 King Edward Road");		
		HotelBooking hb = new HotelBooking("2015 02 19", "2015 03 02" , myCorporateCustomer);
		hbs.calculateBill(hb);
		
		
		IndividualCustomer myIndividualCustomer = new IndividualCustomer("John", 01633, "15 Court Crescent");
		HotelBooking hb2 = new HotelBooking("2015 02 22", "2015 02 28", myIndividualCustomer);
		hbs.calculateBill(hb2);
		
		
		GroupCustomer myGroupCustomer = new GroupCustomer("Jane", 01633, "24 Western Avenue", 10);
		HotelBooking hb3 = new HotelBooking("2015 02 22", "2015 02 28", myGroupCustomer);
		hbs.calculateBill(hb3);
		
		
		List<Customer> customer = new ArrayList<Customer>();
		customer.add(myCorporateCustomer);
		customer.add(myIndividualCustomer);
		customer.add(myGroupCustomer);
	}

}

As you can see at the bottom I've added the 3 customers that I have created to an ArrayList which holds customers. What is the advantage/point of doing this?

Cheers :D
 
  • #47
The main advantage is that you can loop over it to get the hotel billing system to calculate the bill for each customer automatically, I think. For instance you might load them into a list from a database and need to be able to operate your billing system no matter how many customers there are, in the real world you won't just have three customers hardcoded into your main function ;)

Of course with your design it probably makes more sense to put hotel bookings in a list instead, since that's what the hotel billing system operates on - so you might have a list of customers in the system (or a map from customer name to Customer class, for convenience) and then a list of hotel bookings that reference the customers from that list [as a parameter to their constructor] and finally the hotel booking system iterates over that list of hotel bookings and generates bills for each. Right?
 
  • #48
Bacterius said:
The main advantage is that you can loop over it to get the hotel billing system to calculate the bill for each customer automatically, I think. For instance you might load them into a list from a database and need to be able to operate your billing system no matter how many customers there are, in the real world you won't just have three customers hardcoded into your main function ;)

Of course with your design it probably makes more sense to put hotel bookings in a list instead, since that's what the hotel billing system operates on - so you might have a list of customers in the system (or a map from customer name to Customer class, for convenience) and then a list of hotel bookings that reference the customers from that list [as a parameter to their constructor] and finally the hotel booking system iterates over that list of hotel bookings and generates bills for each. Right?

Oh ok that makes sense. Just one quick question, I'm curious as to why the Customer class that I've used is an interface as opposed to an abstract class? Seeing as there are some methods which some customer classes essentially don't use, like IndividualCustomer returning null for discount and extra charge. If this was an abstract class then am I right in saying those methods would just not need to be implemented at all?
 
  • #49
JaAnTr said:
Oh ok that makes sense. Just one quick question, I'm curious as to why the Customer class that I've used is an interface as opposed to an abstract class? Seeing as there are some methods which some customer classes essentially don't use, like IndividualCustomer returning null for discount and extra charge. If this was an abstract class then am I right in saying those methods would just not need to be implemented at all?

You are absolutely right that Customer would be better suited to be an abstract class than an interface, the reason being that all Customer derived classes have exactly the same functionality and only differ in the data they contain (the discounts, charges and name/address/etc). This is made obvious by the fact that the only difference between the different types of customers is their constructor.
 

Similar threads

  • · Replies 7 ·
Replies
7
Views
10K
  • · Replies 14 ·
Replies
14
Views
2K
  • · Replies 6 ·
Replies
6
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 6 ·
Replies
6
Views
3K
  • · Replies 20 ·
Replies
20
Views
6K
Replies
2
Views
3K
Replies
29
Views
5K
  • · Replies 21 ·
Replies
21
Views
5K