The book of visual basic 2005 net insight for classic vb developers 2006 - phần 5 docx

51 362 0
The book of visual basic 2005 net insight for classic vb developers 2006 - phần 5 docx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Mastering Objects 187 This design ensures that you can reuse common pieces of functionality (like the code for the Connect() method) without allowing a programmer to inadvertently create a meaningless object (like an instance of the base DBRecord class). MustOverride In the previous section, you saw how an abstract class can allow you to share code with different derived classes, while remaining safely inactive. Abstract classes also play another role as class templates. To understand how this works, you need to realize that there are some members that you might want to declare in a MustInherit class even though you can realistically supply the code. For example, when you’re designing the DBRecord class, you might decide that all the classes that derive from DBRecord should have basic SaveData() and LoadData() methods, which gives them the ability to update or retrieve a single record. However, you can’t actually write the code to perform this task, because it depends on the type of record. Here’s where the MustOverride keyword fits in. The MustOverride keyword indicates a method whose implementation must be provided by the derived class. In other words, a MustOverride method has no code! For that reason, a MustOverride method can only be placed inside a MustInherit class. Here’s an example: Public MustInherit Class DBRecord Public Sub Connect(ByVal ConnectionString As String) ' Code goes here. End Sub Public MustOverride Sub LoadData() Public MustOverride Sub SaveData() End Class In this example, we assume that the Connect() method, which is used to open a database connection, is standard enough that it can be coded directly into the DBRecord class. However, the other declared methods, which retrieve and save data from the database, have no default implementation that can be given because they depend upon the contents of the database in question and their types. Therefore we leave them to be overriden (actually, imple- mented) by methods in derived classes. When you define a method in an abstract class with MustOverride, you do not specify any code other than the method declaration. You don’t even include a final End Sub statement. The derived class must implement all MustOverride methods declared in its parent. It can’t ignore any of them (unless it too is a MustInherit class). The approach illustrated in this example is a powerful one. It ensures consistency, and it allows you to use classes with different code (for example, an EmployeeRecord and an OrderRecord) in the same way, using common bvb_02.book Page 187 Thursday, March 30, 2006 12:39 PM 188 Chapter 6 methods like Connect(), SaveData(), and LoadData(). However, in .NET it’s more common to create reusable class templates in a different way—using interfaces, which are presented later in this chapter. Multiple-Level Inheritance Visual Basic 2005 allows you to use unlimited layers of inheritance. For exam- ple, we could create a new class called DemocratPolitician, or even President, that inherits from the Politician class, which in turn inherits from the Person class. Some classes pass through many levels of inheritance to build up all their features. For example, every .NET type originates from the ultimate base type System.Object which is enhanced by a number of subsequent derived classes. Figure 6-3 shows the inheritance diagram for a common Windows form. Figure 6-3: The lineage of a Windows form Of course, the architects of the .NET class library are experienced OO developers, and multiple-level inheritance is used to great effect in the class library. In general, however, levels of inheritance should be viewed with cautious skepticism. As a rule of thumb, you should try to keep the levels of inheritance to as few as possible (perhaps just a single level), particularly if the intermediate levels are not used. For example, if your application will only ever use Politicians, it’s best to create only a Politician class, rather than a base Person class and a derived Politician class. Visual Basic 2005 does not allow you to inherit from more than one class at the same time. (This is a limitation of all .NET languages.) If you have multiple classes whose features you want to include in a new class, it’s often best to create a compound class that brings together different subobjects through its properties. These objects can “plug in” to instances of the new System.Object System.MarshalByRefObject System.ComponentModel.Component System.Windows.Forms.Control System.Windows.Forms.ScrollableControl System.Windows.Forms.ContainerControl System.Windows.Forms.Form bvb_02.book Page 188 Thursday, March 30, 2006 12:39 PM Mastering Objects 189 type to provide more features. For example, you could create a Person class that can contain an instance of an Occupation class to specify job-related infor- mation and a Car object that describes the primary vehicle used by that person. Is Inheritance a Good Idea? Inheritance can be a bit tricky to use properly, and with overuse it can lead to more problems than it’s worth. A common problem arising with inheritance is fragile classes. These can emerge when you have a complex hierarchy of objects and multiple layers of inheritance. In such a situation, it’s often extremely difficult to change any characteristics of your base classes, because the changes would affect countless derived classes. In other words, your program reaches an evolutionary dead end, because any enhancement would break existing classes and require a cascade of changes that would be difficult to track down and deal with. When using inheritance, you should ask yourself if there are other avail- able solutions to your problem. In some cases, you can share code by creating a utility class with appropriate functions. For example, you might redesign the DBRecord data object described earlier by placing file access routines into a common class or code module. Another way to avoid inheritance is to design objects that can contain other objects, which in turn provide the desired functionality. This technique is called containment, and it’s usually used in combination with a technique called delegation. For example, suppose you want to create an OrderRecord object with a Connect() method that opens a database connection. You could use contain- ment and delegation to implement this functionality, without inheriting it from a parent class, as follows. First, a DBAccess class is designed whose instances can be used to manage communication with the database. The definition of the OrderRecord class then includes an internal variable of this type. When the OrderRecord.Connect() method is called, it uses the contained DBAccess object in the appropriate way to make the connection. In other words, OrderRecord delegates the responsibility of connecting to DBAccess. Here’s a rough outline of the code: Public Class OrderRecord Private objDB As New DBAccess() Public Sub Connect(ByVal ConnectionString As String) objDB.Connect(ConnectionString) End Sub End Class Using Inheritance to Extend .NET Classes This chapter has concentrated on using inheritance with business objects. Business objects tend to model entities in the real world, and they usually consist of data (properties and variables) and useful methods that allow you to process and manipulate that data. bvb_02.book Page 189 Thursday, March 30, 2006 12:39 PM 190 Chapter 6 Inheritance also allows you to acquire features and procedures from the .NET class library for free. You’ve already seen how to do this with Windows forms, but we haven’t yet discussed the full range of possibilities. This section provides two quick examples designed to illustrate the power of inheritance. Visual Inheritance Every form inherits from System.Windows.Forms.Form. However, you can also make a form that inherits from another form. Here’s how to do it: 1. Start a new Windows project. Rename the form you start off with to BaseForm. This is the form you’ll use as the standard for other forms. 2. Before going any further, add a couple of buttons to BaseForm. Then, right-click your project in the Solution Explorer, and choose Build. 3. Now, choose Project Add Windows Form to add a second form. But instead of starting with the standard blank template, choose the Inherited Form option shown in Figure 6-4. Figure 6-4: Adding an inherited form 4. Name your new form DerivedForm, and click OK. 5. The Inheritance Picker dialog box will show you all the forms in your project (and any other components you’re using). You need to choose the form you want to inherit from. In this case, it’s BaseForm, as shown in Figure 6-5. 6. Click OK. bvb_02.book Page 190 Thursday, March 30, 2006 12:39 PM Mastering Objects 191 Figure 6-5: Choosing the base form Your new form, DerivedForm, will contain all the controls you created on BaseForm. In fact, DerivedForm will look exactly the same as BaseForm, because it will have inherited all of BaseForm’s controls and their properties. In the designer, you’ll see a tiny arrow icon next to each inherited control (see Figure 6-6). Figure 6-6: An inherited form in the designer What’s more, any time you make changes to BaseForm, DerivedForm will be updated automatically (although you may have to build the project before Visual Studio will update the display). None of the code will be repeated in the DerivedForm form class code, but it will all be available. For example, if you include a button click event handler in BaseForm, it will take effect in DerivedForm as well. bvb_02.book Page 191 Thursday, March 30, 2006 12:39 PM 192 Chapter 6 The only difference between BaseForm and DerivedForm is that you won’t be able to move or alter the controls on DerivedForm. However, you can still add new controls to DerivedForm, and you can also change form-level properties (like the form caption or dimensions). If you’re curious to take a look behind the scenes (and confirm that inher- itance really is at work), you need to dive into the designer code file for the form. First, select Project Show All Files to reveal it in the Solution Explorer. Then, expand the DerivedForm.vb node to show the DerivedForm.Designer.vb code file. (Chapter 4 has more on the designer code file, which has the auto- matically generated code that Visual Studio creates.) In the DerivedForm.Designer.vb file, check out the class declaration. Instead of seeing this: Public Class DerivedForm Inherits System.Windows.Forms.Form you’ll see this: Public Class DerivedForm Inherits BaseForm In other words, the DerivedForm class inherits from the BaseForm class (which itself inherits from the Form class). As a result, the DerivedForm is a DerivedForm, a BaseForm, and a plain old Form, all rolled into one. Visual inheritance is a strict and somewhat limiting tool. However, if you need to create several extremely similar windows, such as a series of windows for a custom wizard, you can make good use of it. Subclassing a Control You can use a similar technique to extend a .NET control. The following example creates a customized text box that accepts only numeric input. (It’s included as the NumericTextBox project with the samples.) To create it yourself, add the following class to a Windows application: Public Class CustomTextBox Inherits System.Windows.Forms.TextBox ' Override the OnKeyPress method, which fires whenever ' a key is pressed. Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs) ' Call the base method (which raises the KeyPress event). MyBase.OnKeyPress(e) ' Check if the just-typed character is numeric ' or a control character (like backspace). If Char.IsControl(e.KeyChar) = False And _ Char.IsDigit(e.KeyChar) = False Then ' If it isn't, set the Handled property to ' tell the TextBox to ignore this keypress. bvb_02.book Page 192 Thursday, March 30, 2006 12:39 PM Mastering Objects 193 e.Handled = True End If End Sub End Class This is a customized version of the common text box. It inherits everything that the TextBox control has to offer, and overrides one of the existing methods, OnKeyPress(). The OnKeyPress() method is always called when a key is pressed, just before the character appears in the text box. Here you have the chance to examine the character that was typed, and (optionally) refuse it by setting the KeyPressEventArgs.Handled property to True. TIP How did we know there was an OnKeyPress() method to override? By .NET, all Windows controls provide an OnXxx() method for each event they provide. For example, a button has a Click event, so you can assume it also has an OnClick() method that fires just before the event is raised. If you want to react to this action, you can create an event handler (as you saw in Chapter 4), or you can derive a new class and override the related method (as with the custom text box example). Both approaches are functionally equivalent. The difference is in where you place the code and how you can reuse it. To use this class, begin by compiling your application. Then, switch to the design surface of a form. You’ll see the CustomTextBox control appear in the Toolbox automatically (see Figure 6-7). This is a convenience that Visual Studio provides automatically—it searches your code for all classes that derive (directly or indirectly) from System.Windows.Forms.Control and makes them readily available. Now you can drop your custom text box on a form and run your application. You’ll notice that you can only type numeric characters into the text box. Letters and symbols are ignored. This raises an interesting question. If you want to create a text box that rejects certain characters, is it a better idea to handle an event like KeyPress in your form, or to create a whole new custom control? Generally, it’s better to prevent cluttering your application with extra classes, so it’s simpler to keep all your code in the form. However, if you have any complex keystroke-handling logic that you need to share in several different forms, the custom control approach becomes a lot more attractive. Using this technique, you write the code once, and reuse it to your heart’s content. You can even share your control in several separate applica- tions by placing your class in a class library (.dll) project and sharing the component with other programmers. Figure 6-7: A custom control in the Toolbox bvb_02.book Page 193 Thursday, March 30, 2006 12:39 PM 194 Chapter 6 Interfaces The interface is a cornerstone of object-oriented design, particularly for large- scale applications that need to be deployed, maintained, and enhanced over long periods of time. Interfaces require a bit of extra effort to use, and they are often avoided because they provide few immediate benefits. However, over the long term, they help solve common problems that make an appli- cation difficult to extend and enhance. The goal of an interface is to allow you to separate a class’s definition from its implementation. An interface defines a small set of related prop- erties, methods, and events. By convention, interfaces always start with the capital letter I. For example, you could create an interface that collects common file access operations: Public Interface IFileAccess Property IsFileOpen() As Boolean Sub Open(ByVal FileName As String) Sub Close() Sub LoadData() Sub SaveData() End Interface Note that interfaces don’t use the Public or Private keyword in the dec- larations of their members. All the elements in an interface are automatically public. You’ll also notice that interfaces don’t define their members—in particular, they leave out the End statement and only include the signatures of properties and methods. An interface contains absolutely no real code. It’s a bare skeleton that describes the members needed to support a specific feature or procedure. The IFileAccess interface requires a class to provide its functionality—opening and closing a file, and loading and saving data. In that respect, an interface is very similar to an abstract MustInherit class that is entirely composed of empty MustOverride methods. To use an interface in a class, you use the Implements statement. A class can implement as many interfaces as it needs. However, the class needs to provide its own code for every member of the implemented interface. Con- sider this example: Public Class PersonData Implements IFileAccess End Class bvb_02.book Page 194 Thursday, March 30, 2006 12:39 PM Mastering Objects 195 As soon as you enter this information in Visual Studio, the IntelliSense feature will underline the word IFileAccess to indicate that your class cannot be considered complete, because one or more member declared in the IFileAccess interface has not been defined in PersonData (see Figure 6-8). Figure 6-8: An unimplemented interface To fully implement an interface, you need to provide code for every method. Here is an example of how you would implement the Open() method: Public Sub Open(ByVal FileName As String) Implements IFileAccess.Open ' (Code omitted.) End Sub NOTE Visual Studio has a fantastic shortcut for implementing interfaces. Just type in the Implement line, and then press ENTER. It will automatically fill in every required method for you, with the correct accessibility, data types, and so on. Of course, it’s still up to you to add the code. Inheritance Versus Interfaces The difference between inheritance and interfaces is that inheritance is used to share code, whereas interfaces are used to standardize it. Interfaces guar- antee that several classes all present a standard set of methods to their clients, even when the implementation details are class-specific. In the IFileAccess example, interfaces are a good idea, because while saving data to and loading data from a file is a common operation that several classes need to support, the code for the SaveData() and LoadData() methods will depend on the type of data being saved and loaded, and vary from class to class. (Of course, these methods might themselves use a common .NET component or a custom file access class to take care of some of the heavy lifting and reuse some code.) bvb_02.book Page 195 Thursday, March 30, 2006 12:39 PM 196 Chapter 6 Using Interfaces If you are new to interfaces, you’re probably wondering why you should use them at all when they clearly require so much work. Unlike inheritance, interfaces do not let you reuse blocks of code; in order to share code, you have to make careful use of utility functions or inheritance in addition to interfaces. Interfaces also have the drawback of inflexibility (you always have to implement every member of the interface) and extra syntax (every member definition requires an additional Implements statement to match it to the method, property, or event that it implements). So what benefit does an interface provide? In fact, interfaces aren’t nearly as crazy as they look. First of all, you need to understand that interfaces are not designed to solve problems of code reuse. Instead, an interface is a contract that guarantees that a class offers a certain set of features. A client program may not know anything about a new SalesInfo class, but as long as it knows that the class implements the IFileAccess inter- face, it knows that the class provides LoadData() and SaveData() methods (and how they are used). Or, consider a Microwave and a ToasterOven object, both of which use a similar control panel to cook food. This could be modeled as an interface ( ICookFood), which would allow a client to make dinner without necessarily needing to use any microwave-specific or toaster oven–specific functions. Inheritance provides a similar standardization mechanism. As you learned earlier, you can cast an object to its parent’s type to provide a get access to a basic set of functions and features. (For example, you can treat any Person-derived class as a Person.) The same is true with interfaces. Imagine the following class, which implements the IFileAccess interface: Public Class SalesInfo Implements IFileAccess ' (Code omitted.) End Class The SalesInfo class is standardized according to the IFileAccess interface. As a result, you could pass a SalesInfo object to any method that understands the IFileAccess interface. Here’s an example: Public Sub PrintFileInfo(DataObject As IFileAccess) ' Interact with the object (which is a SalesInfo in this example) ' through the IFileAccess interface. DataObject.Open() DataObject.LoadData() ' (Printing code omitted.) DataObject.Close() End Sub bvb_02.book Page 196 Thursday, March 30, 2006 12:39 PM [...]... right-click it, and choose Properties You’ll see a window like the one shown in Figure 7 -5 Figure 7 -5 : The assembly information As s em bl ies a n d C om p one nt s 219 bvb_02 .book Page 220 Thursday, March 30, 2006 12:39 PM If you scroll to the bottom of the AssemblyInfo .vb file (or look at the bottom of the Assembly Information dialog box in Figure 7-4 ), you’ll find the most important piece of information... experience to learn how to implement object-oriented designs A substantial part of the art of using objects is deciding how to divide a program into classes That question has more to do with the theory of application architecture than with the Visual Basic 20 05 language For example, you may be interested in learning the basics about three-tier design Three-tier design is the idea that applications should be... design 210 C h ap te r 6 bvb_02 .book Page 211 Thursday, March 30, 2006 12:39 PM 7 ASSEMBLIES AND COMPONENTS Some of the most remarkable changes to the way VB developers do business in the NET world stem from the introduction of assemblies, NET s catch-all term for executable application files and compiled components In Visual Basic 6, creating and reusing a component was often tricky, especially if... directory like C:\Program Files\ Microsoft Visual Studio 8\ SDK\v2.0\Bin, depending on where you have installed the NET Framework and what version of Visual Studio you’re using The easiest way to launch ILDasm is to first start the Visual Studio command prompt (choose Programs Visual Studio 20 05 Visual Studio Tools Visual Studio 20 05 Command Prompt) and then type ildasm at the command line Once you run ILDasm,... Show All Files, and then look for the file under the My Project node in the Solution Explorer (see Figure 7-3 ) Inside this file, you’ll see a number of assembly attributes Figure 7-3 : The hidden AssemblyInfo .vb file Each of the attributes in the AssemblyInfo .vb file embeds a single piece of information into your compiled assembly Here’s what the attributes look like (with some sample information added):... strict type of relationship, referred to as an is-a relationship For example, most would agree that a Politician is a Person However, there are many other types of relationships in the world of objects One of the most common is the has-a relationship—and as many can attest, in the materialistic world of today, what a person has is often more important than who they are The same is true for classes,... choose the Application tab, and then click the Assembly Information button Figure 7-4 shows what you’ll see 218 C h ap te r 7 bvb_02 .book Page 219 Thursday, March 30, 2006 12:39 PM Figure 7-4 : Modifying assembly metadata the easy way Taken together, these options replace the project properties used in classic versions of Visual Basic If you’re curious to see where this information ends up, just compile... AssemblyDescription("Test VB 20 05 I/O features.")> AssemblyCompany("No Starch Press, Inc.")> AssemblyProduct( "The No Starch VB 20 05 Examples")> AssemblyCopyright("Copyright 2006" )> AssemblyTrademark("No Starch(TM)")> You can change all of these details by hand, but you don’t need to; the same information is available in a Visual Studio designer Just double-click the My Project node in the Solution Explorer, choose the Application... Version Trackers The manifest also records information about the current versions of all the included files Whenever you compile a VB 20 05 program, this version information is written into the manifest automatically, meaning that there’s no possibility for it to become out of date, or not be synchronized with the underlying application code The manifest also contains a short block of cryptographic... "Smith", 15) ' Create a new family Dim TheFamily As New NuclearFamily(John, Lucy) ' Add the children TheFamily.Children.Add(Anna) TheFamily.Children.Add(Eor) ' Find the youngest child MessageBox.Show( "The youngest is " & TheFamily.FindYoungestChild.FirstName) M a s te rin g O bj ect s 2 05 bvb_02 .book Page 206 Thursday, March 30, 2006 12:39 PM The result of all this is shown in Figure 6-1 0 There isn’t . Figure 6-3 shows the inheritance diagram for a common Windows form. Figure 6-3 : The lineage of a Windows form Of course, the architects of the .NET class library are experienced OO developers, . BaseForm. This is the form you’ll use as the standard for other forms. 2. Before going any further, add a couple of buttons to BaseForm. Then, right-click your project in the Solution Explorer,. it’s BaseForm, as shown in Figure 6 -5 . 6. Click OK. bvb_02 .book Page 190 Thursday, March 30, 2006 12:39 PM Mastering Objects 191 Figure 6 -5 : Choosing the base form Your new form, DerivedForm, will

Ngày đăng: 13/08/2014, 08:21

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan