Discussion 5: OOP and Subtypes
Over the past two lectures, we’ve begun to discuss object-oriented programming. We introduced user-defined types as a mechanism for bundling together problem-specific states and behaviors. Next, we introduced interfaces and subtype relationships as a way to model hierarchical relationships between types and enable polymorphism within our code. In today’s discussion, you’ll explore how user-defined types are modeled and practice working with the subtyping rules in Java.
Learning Outcomes
- Write an instance method given its specifications that accesses the values of its object's fields.
- Compare and contrast static types and dynamic types.
- Explain the benefits of leveraging polymorphism in object-oriented code.
- Describe the principle of dynamic dispatch and the compile-time reference rule.
Throughout the discussion, we’ll consider writing some code that a mock insurance company could use to keep track of their policies (of course, the insurance industry is much more sophisticated than anything we’re doing here!). We can think of an insurance policy as a collection of different covered entities. Each of these entities contributes some amount to the cost of the policy, and the policy covers damages to that entity until some coverage endpoint. We can model these entities with an interface, Insurable, that supports these common behaviors.
Insurable.java
House class. Houses have an address, contain a certain number of bedrooms and bathrooms, and a current market value. Fill in the body of the constructor to initialize these fields with the corresponding parameters.
House.java
f() call frame after the initialization of home in the following code snippet.
Houses to insurance policies, we'll have the House class implement Insurable. To do this, we'll need to add definitions for the three Insurable methods. Suppose that isInsured() and policyExpiration() were taken care of (including adding any additional fields to support these behaviors). Add a definition of premium() to the House class. A house's insurance premium is equal to its current value times some multiplier that the insurance company determines from the house's address (factoring in things such as climate risk, traffic, neighborhood characteristics, etc.). Assume that this multiplier can be obtained by calling a static method rateMultiplier() which accepts the address String as its only argument and returns a double.
House.java
Car class that also implements the Insurable interface. To save space, we've elided the class/field specs and some methods.Car.java
static method totalPolicyCost() to compute the total cost of an insurance policy, which we model as an array of Insurables.
Insurable and Insurable[] even though the interface type Insurable cannot be instantiated? What benefits can this offer in our code?
home:car:policy[1]:car to an entry of policy, even though their static types are different.
policy[0].premium()? Which method body would we enter if we execute policy[1].premium()? How does Java make this determination?
policy[1].mileage() within the simulate() method? Explain your answer.
premium() method for the first time. The bottom call frame in your diagram should correspond to the simulate() method.
Car class from above to also implement the following Vehicle interface.
Vehicle.java
Boat implements Vehicle (but does not implement Insurable).
House, Car, Boat, Insurable, and Vehicle.