嗔秤戻幣�哉膵�云利匈嬉蝕湊蛸賜�塋床四衲���萩晦編報炎嘔囚^泡仟 ̄云利匈��
源平慎弌傍利 卦指云慕朕村 紗秘慕禰 厘議慕尺 厘議慕禰 TXT畠云和墮 〆辺茄欺厘議箝誓匂〇

VB2008貫秘壇欺娼宥(PDF鯉塀哂猟井)-及35何蛍

酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何! 泌惚云慕短嗤堋響頼���誅卒亮茂�俊彭堋響��辛聞喘貧圭 "辺茄欺厘議箝誓匂" 孔嬬 才 "紗秘慕禰" 孔嬬��



    Function CreateIne��ByVal amount As Double�� As ITaxIne 

    Function CreateTaxAccount�┌� As ITaxAccount 

End Interface 


´´´´´´´´´´´´´´´´´´´´´´Page 196´´´´´´´´´´´´´´´´´´´´´´´

174       CH AP T E R   7   *    L E A R N IN G   AB OU T   CO M P O N E N TS   AN D  C L AS S  H I E R AR C H IE S 



               We have four interfaces here�此 �ITaxIne�察�ITaxDeduction�察�ITaxAccount�察�and ITaxEngine。  

          ITaxIne and ITaxDeduction are pure behavioral interfaces。 Pure behavioral means the inter

          face does one thing�察�but it might be implemented in conjunction with other interfaces。 ITaxEngine  

          and ITaxAccount are behavioral functional interfaces。 Behavioral functional means that the  

          interfaces are typically implemented by themselves�察�and usually not with another interface。 

               For example�察�you might implement a Swiss tax system where there are two classes�察�defined  

          as follows�此�



          Class SwissTaxEngine 

              Implements ITaxEngine 

          End Class 



          Class SwissTaxAccount  

              Implements ITaxAccount 

          End Class 



               And if you wish to implement an American tax system�察�the two classes would be defined  

          as follows�此�



          Class AmericanTaxEngine 

              Implements ITaxEngine 

          End Class 



          Class AmericanTaxAccount 

              Implements ITaxAccount 

          End Class 



               The user of either the American or Swiss tax system will not know the specific details of  

          those tax systems。 Initially�察�users would need to determine which tax system they wished to  

          use。 This decision is made using something called a factory�察�as explained in the uping  

          ^Abstracting Instantiations with Factories ̄ section。 



          Implementing a Base Class Tax Engine 



          Whenever you define interfaces�察�you will need to implement them。 In most cases�察�you will  

          create a MustInherit base class that provides a certain amount of default functionality。 The  

          MustInherit base class serves the same purpose as outlined in the previous chapter�此�to provide  

          a certain amount of basic functionality。 

               In the case of the tax engine�察�we need to implement the ITaxEngine interface and provide  

          default implementations for some methods。 The following is the plete base class  

          implementation。 



          Public MustInherit Class BaseTaxEngine  

              Implements ITaxEngine 



              Protected _calculatedTaxable As Double 



              Public Overridable Function CalculateTaxToPay��ByVal account As ITaxAccount�� _ 

                  As Double Implements ITaxEngine。CalculateTaxToPay 


´´´´´´´´´´´´´´´´´´´´´´Page 197´´´´´´´´´´´´´´´´´´´´´´´

                           CH AP T E R   7   *    L E AR N IN G   AB O U T   CO M P O N E N TS   AN D   C L AS S  H I E R AR C HI E S 175 



        _calculatedTaxable = 0。0 



        For Each ine As ITaxIne In account。Ine 

            If ine IsNot Nothing Then 

                _calculatedTaxable = _calculatedTaxable �� ine。TaxableAmount 

            End If 

        Next 



        For Each deduction As ITaxDeduction In account。Deductions 

            If  deduction IsNot Nothing 

                _calculatedTaxable = _calculatedTaxable deduction。Amount 

            End If 

        Next 



        Return account。GetTaxRate��_calculatedTaxable�� * _calculatedTaxable 

    End Function 



    Public Overridable Function CreateDeduction��ByVal amount As Double�� _ 

        As ITaxDeduction Implements ITaxEngine。CreateDeduction 

        Return New TaxDeduction��amount�� 

    End Function 



    Public Overridable Function CreateIne��ByVal amount As Double�� As ITaxIne _ 

        Implements ITaxEngine。CreateIne 

        ' Second argument is the tax rate 

        Return New TaxIne��amount�察�1。0�� 

    End Function 

    Public MustOverride Function CreateTaxAccount�┌� As ITaxAccount _ 

        Implements ITaxEngine。CreateTaxAccount 

End Class 



     The base class must implement all interface methods�察�regardless of whether or not the method  

has an implementation。 The CalculateTaxToPay�┌��察�CreateDeduction�┌��察�and CreateIne�┌�  

methods have implementations。 The CreateTaxAccount�┌� method does not have an implemen

tation and is declared as MustOverride。 The methods with implementations have an Overridable  

keyword associated with them�察�indicating any class derived from BaseTaxEngine can override  

the functionality if they don¨t like the default functionality。  

     In the implementation of CalculateTaxToPay�┌��察�the ine ��account。Ine�� is added  

together and deductions ��account。Deductions�� are subtracted from the ine。 The resulting  

total is used as a query amount ��account。GetTaxRate�┌��� to retrieve the actual tax rate used to  

calculate against the payable tax。 



*Note  The implementation of CalculateTaxToPay�┌� is a shared functionality�察�which implies that there  

cannot be any code specific to a derived type。 All of the calculations and data manipulations are executed  

against an interface�察�making it possible to generalize operations。 Whenever you implement base class methods or  

shared pieces of code�察�you should try to keep the source code derived class´agnostic。 


´´´´´´´´´´´´´´´´´´´´´´Page 198´´´´´´´´´´´´´´´´´´´´´´´

176       CH AP T E R   7   *    L E A R N IN G   AB OU T   CO M P O N E N TS   AN D  C L AS S  H I E R AR C H IE S 



          Overriding for Specialized Functionality 



          In the base class implementation�察�the data member _calculatedTaxable is declared as Protected。  

          As you learned in the previous chapter�察�this means that _calculatedTaxable can be manipu

          lated in a derived class。 However�察�if you look at how the data member is used�察�you will see that  

          only CalculateTaxToPay�┌� assigns the data member。 The purpose of the data member is to  

          provide information about the operation CalculateTaxToPay�┌� without giving the exact details  

          of the operation。 

                The idea behind _calculatedTaxable and the declaration of CalculateTaxToPay�┌� is to  

          provide a mechanism where the derived class does not need to calculate things again。 Consider  

          the example of a country where�察�if your taxable ine is above 400 currency units�察�a surtax of  

           10 currency units is calculated。 You don¨t know what your taxable ine is until the function  

          CalculateTaxToPay�┌� is executed�察�and that function returns only the total payable taxes。 So  

          how do you know if you should apply the surtax in this situation�拭�One solution is to reverse

          calculate the payable taxes�察�but that would involve quite a few additional steps。 An easier solution  

          is to write some code in the base class method of CalculateTaxToPay�┌� that stores the taxable  

          ine so the subclass has access to it。 

                The original implementation of CalculateTaxToPay�┌� does not consider a surtax�察�so the  

          derived class must contain that functionality。 Since CalculateTaxToPay�┌� can be overridden  

          without the data member _calculatedTaxable�察�the derived class would need to implement the  

          functionality in the base class to calculate whether or not the surtax applies。 Following is an  

          sample derived class implementation of the tax engine for such a situation�察�stored in a namespace  

          called Surtax�察�to distinguish it from the base functionality。 



          Namespace Surtax 

              Friend Class TaxEngine  

                  Inherits BaseTaxEngine 



                  Public Overrides Function CalculateTaxToPay��ByVal account As ITaxAccount�� _ 

                    As Double 

                      Dim taxToPay As Double = MyBase。CalculateTaxToPay��account�� 

                      If _calculatedTaxable 〃 400 Then 

                          taxToPay = taxToPay �� 10 

                      End If 

                      Return taxToPay 

                  End Function 



                  Public Overrides Function CreateTaxAccount�┌� As ITaxAccount  

                      Throw New Exception�─�The method or operation is not implemented。;�� 

                  End Function 

              End Class 

           End Namespace 



                In the implementation of CalculateTaxToPay�┌��察�we replace the Overridable keyword with  

          Overrides�察�implying that the functionality of TaxEngine replaces the functionality of BaseTaxEngine。   

          Since our fictional country calculates the basic tax similarly to most countries�察�the functionality  

          of BaseTaxEngine。CalculateTaxToPay�┌� can be used。 Thus�察�the first line of TaxEngine。 

          CalculateTaxToPay�┌� is MyBase。CalculateTaxToPay�┌��察�meaning the base class ��BaseTaxEngine��  

          method CalculateTaxToPay�┌� is called。 


´´´´´´´´´´´´´´´´´´´´´´Page 199´´´´´´´´´´´´´´´´´´´´´´´

                              CH AP T E R   7   *    L E AR N IN G   AB O U T   CO M P O N E N TS   AN D   C L AS S  H I E R AR C HI E S 177 



      Calling the base class results in calculating a basic tax to pay amount。 We need to figure out  

if a surtax applies�察�and that is where the protected data member _calculatedTaxable es into  

play。 Having called BaseTaxEngine。CalculateTaxToPay�┌��察�the data member _calculatedTaxable is  

assigned and contains the amount that is being taxed。 Thus�察�TaxEngine。CalculateTaxToPay�┌�  

can make a decision if more than 400 currency units have been earned。 And if so�察�then the vari

able taxToPay is incremented with another 10 currency units。 Had _calculatedTaxable not  

existed�察�TaxEngine。CalculateTaxToPay�┌� would have needed to call the base class functionality  

to get the basic tax rate�察�and then recalculate the taxable monies to figure out if the surtax applied。 



*Note  When you use Overrides with methods�察�you are saying that you need something special。 This does  

not imply that the base class functionality will be called。 It implies that you might call the base class functionality  

and perform some additional operations。 Thus�察�when designing base class functionality�察�it is important to  

track calculations or operations using protected data members。 The data members avoid having derived classes  

perform the same operations multiple times�察�slowing down the application and avoiding potential errors。 



                                              USING NAMESPACES 



   Namespaces are used to define classes�察�interfaces�察�and structures that belong together。 In this chapter¨s  

   example�察�there is an American tax engine�察�a Swiss tax engine�察�and so on。 For organizational purposes�察�each  

   should have its own namespace。 Sometimes you might even create a custom assembly for each set of inter

   face implementations�察�but you would still need to create a namespace。 Creating a namespace is independent  

   of the fact of whether or not you create a separate assembly。 

         In the examples�察�I use namespaces like Surtax and Canada。 Whenever you create a class or a module�察 �

   or some other type�察�you can embed the type within the namespace。 Then to use the newly defined  

   namespaces in code pieces that are not part of the namespace�察�use the Imports keyword。  



Abstracting Instantiations with Factories 



Take a good look at the scope declaration of the tax engine shown earlier and pare it with  

the scope declaration for the ITaxEngine interface。 What you will notice is that  ITaxEngine is  

declared as Public scope�察�as is BaseTaxEngine�察�and TaxEngine is declared as  Friend。 Going back  

to our project structure�察�this scope declaration implies that any reference to LibTax will see the  

interface ITaxEngine and  BaseTaxEngine�察�but not TaxEngine。 For example�察�the following test  

code will not work。 



Dim taxengine As ITaxEngine = New Surtax。TaxEngine�┌� 



      The reason the test code will not work is that any type that is not declared with Public scope  

is private to the solution containing the declaration。 You may be thinking�察 �That¨s great!you  

declare a type that you cannot instantiate。 So�察�how can I use that type�拭院�

      The scope declarations are not a mistake and illustrate a design pattern called a factory 。 A  

factory is a way of abstracting the instantiation away from the caller so that the interface can  

vary from its implementation。 In our restaurant analogy�察�it means when you want a waiter�察�you  


´´´´´´´´´´´´´´´´´´´´´´Page 200´´´´´´´´´´´´´´´´´´´´´´´

178       CH AP T E R   7   *    L E A R N IN G   AB OU T   CO M P O N E N TS   AN D  C L AS S  H I E R AR C H IE S 



           don¨t want to need to know his name。 You would rather have a generic mechanism where the  

           restaurant presents to you the waiter。 Otherwise�察�to eat at a restaurant�察�you would need to  

           know the name of your waiter before being able to order something。 That would be inefficient。 

                The correct way of defining a factory is as follows�此�



              Public Module EngineCreator  

                  Public Function CreateSurtaxTaxEngine�┌� As ITaxEngine  

                      Return New Surtax。TaxEngine�┌� 

                  End Function 



                  ' Required for country´specific tax calculations 

                  Public Function CreateCanadianTaxEngine�┌� As ITaxEngine 

                      Return New Canada。TaxEngine�┌� 

                  End Function 

              End Module 



                The factory is typically declared in a module because a module is not instantiated。 Generally  

           speaking�察�you don¨t want to add a factory to an object that can be instantiated because it could  

           result in context´specific instantiation。 In other words�察�you usually want a fresh object created  

           from scratch each time�察�so it¨s not affected by the current state of the application。 In the imple

           mentation of CreateSurtaxTaxEngine�┌��察�the type Surtax。TaxEngine is instantiated�察�and the  

           instance is cast to the interface type ITaxEngine。 

                The EngineCreator module is declared with public scope�察�implying any code that references  

           the assembly can see the module。 Thus�察�the test code can be rewritten as follows ��we need to  

           import the LibTax project�察�of course���此�



           Dim taxengine As ITaxEngine = EngineCreator。CreateSurtaxTaxEngine�┌� 



                After calling  EngineCreator。CreateSurtaxTaxEngine�┌��察�the test code has a valid instance of  

           ITaxEngine。 It¨s very important to note that the test code has no idea what type implemented  

           the interface。 This allows the
卦指朕村 貧匯匈 和匯匈 指欺競何 壘��16�� 家��13��
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何!
梁椣戻幣�� 梁心弌傍議揖扮窟燕得胎��傍竃徭失議心隈才凪万弌誌育断蛍�輌臆惨軼僑〃�燕慕得珊辛參資誼持蛍才将刮襲潜��範寔亟圻幹慕得 瓜寡追葎娼得辛參資誼寄楚署衛、持蛍才将刮襲潜填��