Composition happens when an object is made up of other objects. For example, in a card game, we might represent a Deck as made up of an array of Card objects:
Composition is also known as a Has-A relationship. (A Deckhas an array of Cards). Put formally, the Deck is the aggregating class, and the Card class is is the aggregated class.
When we draw a UML diagram involving composition, as in Figure A.2.2, we use an arrow with a diamond head to indicate aggregation, and we can also add notation here that shows that one Deck contains many Card objects.
The first two of these are built by the toaster company. But the company that makes toasters doesn’t build the power supply or the dial (which has circuitry to control the current flow). Instead, those are parts they order from some other companies and put into the chassis.
That means that our Toasterhas-aPowerSupply object and has-aDial object. Figure A.2.3 shows the UML diagram. You can see the full code in the file ch14/ToasterTest.java in the repository.
Before we see how composition affects the way we construct and manipulate objects, let’s give a few more instances of composition (has-a) relationships. Using composition reflects the way objects are built out of other objects (parts). Each of the sub-parts has its own attributes and things that it can do (its methods). Notice that we sometimes need multiple instances of a sub-part when constructing the larger object.
publicPowerSupply(int voltage){if(voltage ==220){this.voltage = voltage;}else{this.voltage =110;}// new power supplies are always turned offthis.turnedOn =false;}publicDial(int minValue,int maxValue){this.minValue = minValue;this.maxValue = maxValue;// new dials are always set to lowest valuethis.dialValue = minValue;}
Now, look at how the Toaster class starts, with line numbers for reference:
The constructor in line 7 has two parameters: the number of slots in the toaster and what voltage it should have. The number of slots and number of slices of bread currently in the toaster are attributes belonging to the Toaster class, and those get set directly.
The power supply is an object, which is why line 10 has to call the PowerSupply constructor to build a power supply with the desired voltage. Think of this as the toaster company calling up the power supply company and telling them “send me a 110-volt power supply” and putting that power supply into the finished toaster.
Although a real-life toaster is composed of parts, all of the controls are on the toaster’s exterior. We don’t expect—or want—the customer to have to directly access the power supply to turn the toaster on! Similarly, we want to provide methods in the Toaster class that will give programs that use the class access to the private methods and attributes of power and darkness:
That’s a lot of duplicated code when we translate it to Java. If we can use the extends keyword to say that ElectricBicycle extends Bicycle, that means that ElectricBicycleinherits all of Bicycle’s methods and attributes. All we have to include now in ElectricBicycle are the attributes and methods that add extra capabilities to an electric bicycle, as shown in Figure A.2.9:
In this example, Bicycle is called the superclass or parent class, and ElectricBicycle is called the subclass or child class. We use an open-headed arrow pointing from the subclass to the superclass in the UML diagram. As in the real world, the child inherits things from the parent 1
With one exception: as the joke says, “Parents inherit their gray hair from their children.”
In this exercise, we will explore has-a and is-a relationships. First, state whether the relationship of the following classes is composition or inheritance, and draw the UML diagram showing that relationship. (You don’t need to provide attributes or methods in the diagrams; the class name alone will be sufficient.)
For classes that exhibit the inheritance relationship, could you name a few data fields/attributes for the superclass? Could you name a few for the subclass only?
For example, Teacher (subclass) is-a Person (superclass). Data fields for Person are: name, age, address, etc. Data fields for Teacher are: school, hire date, etc.
Let’s use a smaller example for our continued discussion of inheritance. We’ll have an Item class, which represents an item in a store. An Item instance has a name, a SKU (stock keeping unit), and a price. This is the parent class. We also have a SaleItem class, which is a child class. In addition to a name, SKU, and price (which it inherits from the parent class), a SaleItem has a discount percentage (expressed as a decimal). Figure A.2.11 shows the UML diagram for these two classes:
publicclassSaleItemextendsItem{privatedouble discount;// as a decimalpublicSaleItem(String name,String sku,double price,double discount){this.name = name;this.sku = sku;this.price =Math.abs(price);this.discount =Math.max(0,Math.min(discount,1.00));}}
But that won’t work, because name, price, and sku are private to the Item class. We can’t call the setter methods for name and sku because there aren’t any. What we need to do is call the superclass constructor, which can set those attributes. To call a superclass constructor, you use the keyword super:
Again, because name, sku, and price are private to the Item class, the purchase, toString and equals methods must use the getter methods to access those private values.
Letter Size Envelopes - 100 count (LSE-0100): $5.75
Ten boxes of envelopes cost $57.50
Erasable marker - black (EMB-913): $2.15 - 10.0% discount
Ten markers cost $19.35
Congratulations! We’ve used inheritance, and our program works. Now it’s time to do what Joe Armstrong said in his book Erlang and OTP in Action: “Make it work, then make it beautiful, then if you really, really have to, make it fast. 90 percent of the time, if you make it beautiful, it will already be fast. So really, just make it beautiful!”
Part of making a program beautiful is getting rid of unnecessary duplication. In that spirit, let’s take a closer look at the SaleItem class’s purchase, toString and equals methods. The calculation of the base price in purchase is the same as in Item. The part of toString’s format string for the name, sku, and price is the same as in Item. Similarly, the first three lines of equals are the same as in Item.
Design a class named Person with two subclasses: Employee and Customer. The attributes for these classes are described in italics. A Person has a name, address, phone number, and email address.
A Programmer and a Tester have a cubicle number. Both will receive a fixed bonus at the end of the year.
A Manager has an office number and has a variable bonus based on the performance of their team. This means that a Manager should have attributes for the target bonus amount and the performance percentage.
Draw the UML diagram showing the relationship of these classes, then code all these classes showing the data fields and attributes. Make meaningful names for the attributes and give them an appropriate data type. (You do not need to create constructors or other methods for the classes.)
The XYZZY Corporation wants to retain their most loyal customers. They launch a customer retention program and offer discount to customers who have been purchasing from the company for at least one year.
Write a subclass PreferredCustomer that extends the Customer class from the preceding exercise. The PrefCust class should have two data fields: average annual purchase amount (average dollar amount purchased per year) and years (number of years they have been a customer). These are both private variables.
Customers get a discount percentage based on their years as a customer and average purchase amount. There are three levels of Preferred Customers: bronze, silver, and gold.
Write the PrefCust class with all its data fields. Please write all the getter and setter methods. Write a method named getDiscount that uses the average annual purchase amount and years as a customer to return the discount percent (as a percentage).
In this exercise, you will implement an Account class which represents a bank checking account. You will then create two classes that inherit from Account: SavingsAccount and CreditCardAccount.
You will then use composition to create a Customer class which includes instances of each of these account classes. Finally, you will write a program with a main method that works with these classes.
Create a two-parameter constructor that takes an account number and balance. Make sure that the balance is always greater than zero (Hint: Math.abs)
Implement getters and setters: getNumber(), getBalance(), and \newline setBalance(double newBalance). There is no setNumber method—once an account is created, its account number cannot change.
Implement these methods: void deposit(double amount) and \newline void withdraw(double amount). For both these methods, if the amount is less than zero, the account balance remains untouched. For the withdraw method, if the amount is greater than the balance, it remains untouched. These methods do not print anything.
Implement a toString method that returns a string with the account number and balance, properly labeled.
Part 2: Next, implement the SavingsAccount class. It inherits from Account and adds a private apr property, which is the annual percentage rate (APR) for interest.
Write a three-argument constructor that takes an account number, balance, and interest rate as a decimal (thus, a 3.5% interest rate is given as 0.035). Make sure that the interest rate is never less than zero.
Add a getter and setter: getApr() and setApr(double apr). The setter must ensure that the APR is never less than zero.
Write a calculateInterest instance method that returns the annual interest, calculated as the current balance times the annual interest rate.
Modify toString to include the interest rate. IMPORTANT: The value returned by the toString method must not include the calculated annual interest.
A four-argument constructor that takes an account number, balance, interest rate as a decimal (thus, a 3.5% interest rate is given as 0.035), and credit limit. Make sure that neither the interest rate nor credit limit can be negative.
Write getters and setters for the apr and creditLimit. The apr setter should leave the APR untouched if given a negative value. The creditLimit setter should leave the credit limit untouched if given a negative value.
Modify toString to include the interest rate and credit limit. IMPORTANT: the value returned by the toString method must not include the monthly payment.
Override the withdraw method so that you can have a negative balance. If a withdrawal would push you over the credit limit, leave the balance untouched. Examples:
If your balance is $300 with a credit limit of $700, you can withdraw $900 (leaving a balance of $-600).
If your balance is $-300 with a credit limit of $700, you can withdraw $350 (leaving a balance of $-650).
If your balance is $-300 with a credit limit of $700, you can not withdraw $500, because that would then owe $800, which is more than your $700 limit.
In short, the maximum amount you can withdraw is your current balance plus the credit limit.
Implement a calculatePayment method that works as follows: If the balance is positive, the minimum amount you have to pay on your card per month is zero. Otherwise, your monthly payment is the minimum of 20 and $(apr/12) \cdot (−balance)$