10.2 Inheritance

At this point in the book, your programming style is starting to become more sophisticated. No longer are you writing code where one long file encompasses everything you do. Now you are using objects, and you are also beginning to program in an object-oriented manner. Object-oriented programming (OOP) is a powerful form of programming that is currently extremely popular and the backbone for many new languages, including Ruby.

Gem of Wisdom

Object inheritance is one of the most powerful parts of object-oriented programming. Inheritance enables hierarchical decomposition of structures into logically encapsulated units.

Thus far, we have talked about creating simple objects that are independent of one another. However, one of the most powerful abilities OOP has is the ability to define relationships between objects. The first of these relationships is known as inheritance. To understand the concept of inheritance, imagine a ball (any spherical object that could pass for a ball will do). Perhaps you are thinking of a baseball, a tennis ball, or a ping-pong ball; it does not matter which because all those balls have a large degree of similarity among them, despite being different types of balls or even different objects. If we needed to accomplish some task and asked you for a ball, they could all work despite their differences. Inheritance allows us to define these types of relationships with Ruby objects. This ends up saving the programmer significant time and code because she or he need not redefine parts of the objects that are similar.

Let’s return to our bank account example from the preceding chapter. It defined what is essentially a checking account, and our bank is no longer happy with just this one type of account; now it wants to expand to include savings accounts. The first thing to notice are the similarities between a savings account and a checking account: they both maintain a balance and can have money withdrawn from them and deposited to them. The class that defines the similarities in the relationship is referred to as the parent class, or the superclass.

The main differences between the two bank accounts are that you cannot withdraw beyond the minimum balance from a savings account (we will touch on this in the next section) and that a savings account generates interest. The class that defines the differences in the relationship is referred to as the child class or the subclass. Now we will use inheritance to define this SavingsAccount class (see Example 10-1).

Example 10-1. SavingsAccount version 1
     1 require_relative '../chapter_09/account_5.rb'
     2 
     3 class SavingsAccount < Account
     4 	def initialize(balance, name, phone_number, interest, minimum)
     5 		super(balance, name, phone_number)
     6 		@interest = interest
     7 		@minimum = minimum
     8 	end
     9 
    10 	def accumulate_interest
    11 		@balance += @balance * @interest
    12 	end
    13 end

Note that we use the require_relative command instead of the require command. require loads files that are installed as Ruby libraries or files for which the full path to the file is given. require_relative is used to load files without specifying the full path to the file; it looks for files in a location relative to the file require_relative is used in.

The first thing to note in the code provided in Example 10-1 is the < symbol (on line 3). This is the symbol used to define inheritance in Ruby. In this case, the parent class is the Account class, which is predefined via line 1, and the child class is the SavingsAccount class. See the account class in Example 9-9.

The next thing to look over is the constructor of the SavingsAccount class, expressed by the initialize method on line 4. Immediately, in line 5, this method calls a method named super(), which is the equivalent of calling the initialize method for the superclass Account. After this, we initialize the instance variables @interest and @minimum. It is important to note that these pieces of data distinguish a SavingsAccount from a CheckingAccount and the subclass from the superclass.

Finally, there is the accumulate_interest method, which is just a simple interest calculation.

However, thanks to inheritance, the SavingsAccount class can do more than just accumulate interest. It also inherits all the data and methods from the Account class. Table 10-1 is a summary of everything inherited by the SavingsAccount class.

Table 10-1. SavingsAccount inherited summary

Data

Methods

@balance

withdraw(amount)

@name

deposit(amount)

@phone_number

transfer(amount, targetAccount)

 display

If we create an instance of the SavingsAccount class:

account = SavingsAccount.new(200.00, "Reynolds",
9694905555, 0.015, 150)

we can then call any of the following methods:

account.deposit(amount)
account.withdraw(amount)
account.transfer(amount, targetAccount)
account.accumulate_interest
account.display

This explicitly shows the power of inheritance. Although we never defined four of the five methods shown for the SavingsAccount class, we can use them because they are inherited from the parent class, Account. The SavingsAccount class consists of only 11 lines of code, but it has as much functionality as 41 lines of code (the number of lines of code in Example 10-1 plus Example 9-9).

If we were to return to the transfer(amount, targetAccount) method from the preceding chapter we would see that it was designed to transfer money from one account to another. At the time we created the method, we had not designed a SavingsAccount and were content with it working only on Account objects. However, it will work on SavingsAccount objects, because a SavingsAccount is an Account; it has enough similarity for a transfer between accounts to be possible. This is another powerful ability granted by inheritance, and it is known as polymorphism. Polymorphism, however, does not work both ways. With the transfer(amount, targetAccount) method example, the polymorphism is from the subclass to the superclass. Polymorphism will not work when you are trying to morph from a superclass to a subclass, because the subclass has abilities the superclass does not. To express this in an example, imagine trying to call the accumulate_interest() method from an Account object; it won’t work because only SavingsAccount objects, not Account objects, have the accumulate_interest() method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.245.233