4.2 Inheritance

only for RuBoard

Once upon a time, in a dimly lit cube...

After writing CreditCard , GiftCertificate , and Check classes, a self-realization occurs: "Self, I see that I can group all of the common behavior from these classes into a base class called Payment ." This realization usually happens when you start to see that many classes you work with have the same method names (meaning that they exhibit the same behavior).

This general payment class (shown in Example 4-1) might contain methods to authorize, credit, and bill for a specific amount, as well as associate the payment with an account number. The general rules of the class are that all payments are authorized first, then they are billed. A billed payment may also be credited.

Example 4-1. General Payment class
 Imports System     Public Class Payment       Private account As String   Private amount As Double   Private authorized As Boolean   Private billed As Boolean       Public Sub New(ByVal account As String)     Me.account = account     authorized = False     billed = False     amount = 0   End Sub       Protected ReadOnly Property AccountNumber( ) As String     Get       Return Me.account     End Get   End Property       Public Function Authorize(ByVal amount As Double) As Boolean     If authorized Then       Console.WriteLine("Payment is already authorized")     Else       Me.amount = amount       Console.WriteLine("Authorizing payment for {0:c}", _         amount)       authorized = True     End If     Return authorized   End Function       Public Function Bill( ) As Boolean     If authorized Then       Console.WriteLine("Billing payment for {0:c}", _         amount)       billed = True     Else       Console.WriteLine("Payment is not authorized")     End If     Return billed   End Function       Public Function Credit( ) As Boolean     If billed Then       Console.WriteLine("Crediting payment for {0:c}", _       amount)       billed = False       Return True     Else       Console.WriteLine("Payment has not been billed")     End If     Return False   End Function     End Class 

Account information is considered sensitive. This information would probably be stored in a database somewhere in an encrypted state. When the payment information is retrieved, the account number can be unencrypted and used by the object itself. It never needs to be seen by human eyes. It makes sense, then, that AccountNumber should be a protected property, since derived classes would need access to account information as well. The remaining methods of the class are public.

After grouping this behavior in a base class, you can now extend it through inheritance. As shown in Example 4-2, a specialized classperhaps a credit cardmight need to verify the account number. Also, making the account number readily available outside of the class is unwise. However, in terms of credit card numbers , it is often necessary to display a portion of the number on an invoice. To make this display possible, you can add a DisplayNumber property to the class that returns the account number but hides most significant digits (i.e., 4XXXXXXXXXXX1234 ).

Using the Inherits keyword, you can create a CreditCard class that includes all the public methods from Payment . Additional methods can then be added to the derived class, as shown in Example 4-2.

Example 4-2. Derived CreditCard class
 Imports System Imports System.Text     Public Class CreditCard        Inherits Payment       Public Sub New(ByVal account As String)     MyBase.New(account)   End Sub       Public Sub Verify( )     Console.WriteLine("Verifying...")   End Sub       Public ReadOnly Property DisplayNumber( ) As String     Get       'Faster than concatenating normal strings       Dim sb As New StringBuilder( )       Dim account As String = Me.AccountNumber       Dim len As Integer = account.Length       sb.Append(account.SubString(0, 1))       sb.Append(New String("X"c, len - 5))       sb.Append(account.SubString(len - 4, 4))       Return sb.ToString( )     End Get   End Property     End Class 

Alternatively, inheritance can be declared like this:

 Public Class CreditCard : Inherits Payment       'Methods here     End Class 

Here, the colon signifies a new line of code in VB and mimics the inheritance declaration of C#, C++, and Java. Both definitions are equivalent, and using either is a matter of style. The latter will be used throughout the book, but only for readabilitynot to garner the respect of C++ programmers.

However, there is a problem. Constructors are not inherited, so every class must provide one. Otherwise , the compiler will create an empty one. In fact, if the base class has parameterized constructors but does not have a parameterless constructor, a constructor must be defined explicitly. If it is not, the VB.NET compiler will generate an error.

Before an instance of CreditCard is created, a constructor that passes the account number to the base class must be provided. The MyBase keyword allows a base class method to be called from a derived class, so the task is trivial:

 Public Class CreditCard : Inherits Payment       Public Sub New(ByVal account As String)     MyBase.New(account)   End Sub       Public Sub Verify( )     Console.WriteLine("Verifying {0}", Me.AccountNumber)   End Sub       'Other methods here End Class 

Now that an appropriate constructor is in place, you can create an instance of CreditCard that can use all the public methods from Payment :

 Dim cc As New CreditCard("4111111111111111") cc.Verify( ) If cc.Authorize(3.33) Then   If cc.Bill( ) Then     cc.Credit( )   End If End If 

Remember that everything that is protected in Payment is not available from outside the class:

 'Error - internal use only Dim visa As New CreditCard("4111111111111111") Dim accountNumber As String = visa.AccountNumber But it is available   within   the derived class: Public Class CreditCard : Inherits Payment       Public Sub Verify( )     Console.WriteLine("Verifying {0}", Me.AccountNumber)   End Sub     End Class 

Everything that is private in the Payment class is just that. You can do nothing about it. Private data is not directly accessible outside of the scope where it was declared, regardless of whether it is a derived class or not. And to reiterate (and probably not for the last time), all member data for any class should always be private. [1]

[1] It should be privateat least initially. Relaxing restrictions is easier than enforcing them. Working from a totally public class interface would be more difficult than working from a more restricted one because of interdependencies that could occur during the development cycle.

Base classes should represent a general concept. Therefore, a good rule is to always make your base classes abstract.

Strings Are Immutable

Be careful and considerate when using strings. Strings in .NET are immutable, meaning they cannot be changed. There really is no such thing as appending one string to another, although the following code fragment mistakenly suggests otherwise:

 Dim msg As String = "Hello" msg += ", World!" 

Actually, when two strings are concatenated like this, a third string is created. The string "Hello" is then marked for finalization .

You will often need to compose a string within a loop by appending a value to a master string on each iteration. This is the case with Example 4-2. Do not use String for this purpose. Instead, use the StringBuilder class in System.Text .

4.2.1 Inheritance from System.Object

The Payment class implicitly derives from System.Object , as does CreditCard . This is done automatically; nothing special has to be done because the compiler handles it all.

Inheritance from System.Object provides a common set of functionality for all objects running under .NET. Therefore, each object will have the following standard set of behaviors associated with it:

Equals

This behavior compares objects. You can override this method and make your own determinations about when one of your objects is considered equal to another.

ReferenceEquals

This behavior determines whether two objects share the same reference.

Finalize

This method is called before the garbage collector frees the memory associated with the object. It is not called when the object goes out of scope; rather, it is called whenever the garbage collector deems it necessary. Therefore, you should not rely on this method to free any limited resources that might be associated with your object.

GetHashCode

This method generates a number that represents the object's value. It allows all objects to participate in the hash table implementations provided by .NET.

GetType

This behavior returns an instance of System.Type , which is used heavily in reflection (see Chapter 7). A Type object can be used to find class- related information about an object, such as the methods it has, whether the class is abstract, and the events it publishes.

ToString

This method describes an object by returning a meaningful text string. By default, it returns the name of the class, but it can be overridden. When an object is used in a place that requires a string, this method is called automatically. For example, Console.WriteLine(myObject) results in a call to myObject.ToString .

4.2.2 NotInheritable

VB does not support multiple inheritance; a class cannot be derived from more than one class at the same time . A single inheritance hierarchy can be sustained indefinitely, though, as the following code suggests:

 Public Class Visa : Inherits CreditCard     End Class 

Here, we've defined a Visa class, which inherits from the CreditCard class, which in turn inherits from the Payment class. The Payment class in turn implicitly inherits from the framework's System.Object class.

Eventually, your hierarchies will become very specific, and at some point you may want to prevent further derivation. You can use the NotInheritable modifier to accomplish this goal. This modifier is mutually exclusive with MustInherit , the Visual Basic keyword discussed in the next section:

 Public Class  NotInheritable  DebitCard : Inherits Visa     'Can no longer inherit End Class 

4.2.3 Abstract Base Classes

Considering that there is no generic way to authorize, bill, and credit the various payment types, you should probably make Payment an abstract base class (ABC). An ABC usually contains minimal functionality that can be used by all derivatives, but its main purpose is to serve as a template of sorts. It defines the methods a subclass needs to support to be considered a kind of the base class.

To make Payment an abstract base class, add the MustInherit keyword to the class declaration from Example 4-1. The class declaration then appears as follows :

 Public  MustInherit  Class Payment 

The derived CreditCard class still functions as it did before, but the ABC cannot be instantiated :

 Dim myPayment As New Payment( )    'Error 

Preventing instances of a base class is usually preferable because it represents an idea more than a specific "thing." The specifics are left to the concrete classes that are derived from the base class, such as CreditCard , GiftCertificate , and Check .

only for RuBoard


Object-Oriented Programming with Visual Basic. Net
Object-Oriented Programming with Visual Basic .NET
ISBN: 0596001460
EAN: 2147483647
Year: 2001
Pages: 112
Authors: J.P. Hamilton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net