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

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

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


ted  

           the interface。 This allows the assembly to change which type is referenced in the implementa

           tion of CreateSurtaxTaxEngine�┌� without having to inform the caller of the method。 

                Putting this into the context of the restaurant�察�it means waiters can be replaced。 So if you  

           repeatedly visit a restaurant and get a waiter called John�察�but one day John gets sick and is not  

          working�察�you can still order and receive your food from the waitress called Mary。 It would be a  

           bad idea for a restaurant to depend on a particular server for a particular guest。 



           Using Default Implementations 



           In some cases�察�base classes are not necessary。 Sometimes you can create a default implemen

           tation that could span multiple subsystems。 In the case of the tax engine�察�an ine is an ine  

           in Canada�察�an ine in the United States�察�and an ine in Germany。 What varies is how the  

           ine is treated in each country when calculating taxes。 Another consistency across countries is  

           that if ine is a capital gain�察�not all of the ine is taxable。 

                In the case of ine�察�you can create an implementation that would be identical across  

           different tax engines�察�as follows�此�


´´´´´´´´´´´´´´´´´´´´´´Page 201´´´´´´´´´´´´´´´´´´´´´´´

                           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 179 



NotInheritable Class TaxIne  

    Implements ITaxIne 



    Private _amount As Double 

    Private _taxableRate As Double 



    Public Sub New��ByVal amount As Double�察�ByVal taxableRate As Double��  

        _amount = amount 

        _taxableRate = taxableRate 

    End Sub 

     

    Public ReadOnly Property RealAmount�┌� As Double _ 

        Implements ITaxIne。RealAmount 

        Get  

            Return _amount 

        End Get 

    End Property 



    Public ReadOnly Property TaxableAmount�┌� As Double _ 

        Implements ITaxIne。TaxableAmount 

        Get 

            Return _amount * _taxableRate 

        End Get 

    End Property 

End Class 



     The ITaxIne interface has two properties that are implemented in TaxIne�此�RealAmount  

and TaxableAmount。 The values for the two properties are considered read´only and are defined  

by the constructor of TaxIne。 The purpose of the constructor is to assign two values and  

then consider the object as immutable。 If you wanted to change the values of the ITaxIne  

interface�察�you would need to instantiate a new instance of TaxIne。 While it sounds like a pain  

to need to instantiate a new instance whenever you want to change the value of the RealAmount and  

TaxableAmount properties�察�this approach has some advantages in terms of performance and  

resource management。 

     In the sample code�察�the TaxableAmount property is the result of multiplying the data members  

_amount and _taxableRate。 For example�察�when calculating the taxable ine of a capital gain  

in Canada�察�you multiply the total amount by 50�ァ� Thus�察�the _taxableRate data member would  

have a value of 0。50。 

     Another item to note is that the declaration of TaxIne is lacking a Public scope�察�but has  

a NotInheritable keyword prefixed to the identifier。 When a class is prefixed with NotInheritable�察 �

it means that the class cannot be subclassed。 From a design perspective�察�the code is saying  

TaxIne is a shared class that should not be subclassed lest it affect the shared behavior。  

     The NotInheritable keyword can also be applied to a method�察�which means that the method  

cannot be overloaded or overridden。 You would use NotOverridable on a method when you do  

not want a derived class to change the behavior of the method。 Though to be able to use the  

NotOverridable keyword�察�you first need to define a method that overrides another method。 


´´´´´´´´´´´´´´´´´´´´´´Page 202´´´´´´´´´´´´´´´´´´´´´´´

180       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 



               The implementation of  ITaxDeduction is similar to  ITaxIne�此�



          NotInheritable Class TaxDeduction 

              Implements ITaxDeduction 



              Private _amount As Double 



              Public Sub New��ByVal amount As Double��  

                  _amount = amount 

              End Sub 



              Public ReadOnly Property Amount�┌� As Double _ 

                  Implements ITaxDeduction。Amount 

                  Get 

                      Return _amount 

                  End Get 

              End Property 

          End Class 



               TaxIne and TaxDeduction are sealed classes because the functionality will be shared  

          among implementations。 But is it wise to expose the interfaces and not the classes themselves�拭 �

          Interfaces are used to separate implementation from ideas。 Interfaces change very little�察�whereas  

          implementations can and will change more often。 But if an implementation behaves like an  

          interface in terms of changing interface signature�察�why not just expose the class itself�拭�The  

          answer is that sometimes you will expose the class�察�and sometimes you will expose the interface。  

          For the tax engine�察�exposing the sealed classes TaxIne and TaxDeduction would probably  

          have been fine。 The rule of thumb is that you expose classes only when you are sure that the  

          interface signatures of methods and properties will not change very often。 



          Implementing a Base Tax Account 



          The  ITaxAccount interface is also a candidate for base class functionality。 The implementation  

          of this interface looks like this�此�



          MustInherit Class BaseTaxAccount  

              Implements ITaxAccount 



              Private _deductions��100�� As ITaxDeduction 

              Private _ines��100�� As ITaxIne 



              Public Sub AddDeduction��ByVal deduction As ITaxDeduction�� _ 

                  Implements ITaxAccount。AddDeduction 

                  For c1 As Integer = 0 To 100 

                      If _deductions��c1�� Is Nothing Then 

                          _deductions��c1�� = deduction 

                          Exit For 

                      End If 

                  Next 

              End Sub 


´´´´´´´´´´´´´´´´´´´´´´Page 203´´´´´´´´´´´´´´´´´´´´´´´

                           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 181 



    Public Sub AddIne��ByVal ine As ITaxIne�� _ 

        Implements ITaxAccount。AddIne 

        For c1 As Integer = 0 to 100 

            If _ines��c1�� Is Nothing Then 

                _ines��c1�� = ine 

                Exit For 

            End If 

        Next 

    End Sub 



    Public ReadOnly Property Deductions�┌� As ITaxDeduction�┌� _ 

        Implements ITaxAccount。Deductions 

        Get 

            Return _deductions 

        End Get 

    End Property 



    Public ReadOnly Property Ine�┌� As ITaxIne�┌� _ 

        Implements ITaxAccount。Ine 

        Get 

            Return _ines 

        End Get 

    End Property 



    Public MustOverride Function GetTaxRate��ByVal ine As Double�� As Double _ 

        Implements ITaxAccount。GetTaxRate 

End Class 



     Let¨s take stock of what has been acplished and decide if the tax engine is plete  

from a base functionality perspective。 



     o Ideas have been defined for a plete tax engine。 



     o Some interfaces have been implemented in the form of base classes。 



     o Some interfaces have been implemented as sealed default implementations。 



     The tax engine can be considered plete because all of the interfaces have been defined  

and accounted for from a base functionality perspective as either base classes or default imple

mentations。 It is does not mean that interfaces will always be implemented。 Sometimes some  

interfaces will not have a base functionality or base classes。  

     The important aspect to remember when defining the base functionality is to account for  

all interfaces to serve a purpose。 Do not define an interface as a placeholder for potential future  

functionality。 When seeing an interface�察�a user expects it to serve some type of purpose。  


´´´´´´´´´´´´´´´´´´´´´´Page 204´´´´´´´´´´´´´´´´´´´´´´´

182       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 



           *Note  The rule of thumb for interfaces is that once defined and put into production�察�they are not changed。  

           This rule of thumb is almost written in concrete。 You never change interfaces once they are in production  

           because doing so would wreak havoc!all the code that uses the interface would need to be updated。 In  

           general�察�if you feel the need to change an interface�察�create a new one。 



                With base functionality plete�察�we are ready to implement a tax system for a particular  

           country。 



           Using the Base Functionality of the Tax Engine  

           to Calculate Taxes 



           We will use the base functionality of the tax engine to calculate Canadian taxes。 I chose the  

           Canadian tax system because that is the system that I happen to know and understand�察�and  

           there is plenty of online documentation on how to calculate the tax rate。  



                                        SOME BACKGROUND ON CANADIAN TAXES 



              The first thing I would like to say about Canadian taxes is that Canadians pay too much!way too much。 The  

              second ment is that Canadian taxes are simple�察�in that they don¨t let you write off many deductions ��for  

              example�察�interest payments on your house���察�which brings us back to the first point that Canadians pay way too  

              much。 Of course�察�people in other countries would probably say the exact same thing。 

                   Canadian taxes are based on calculating the tax rate at the federal level and at the provincial level。 Thus�察 �

              to calculate your taxes�察�you need to know in which province and in which year you are paying your taxes。 Canadian  

              taxes change quite a bit depending on the year。 From an implementation perspective�察�it means the tax engine  

              must know about provincial taxes�察�federal taxes�察�and which year。 

                   Capital gains in Canada are calculated on a 50�ァ�basis。 This means if I made a capital gain of 200 Canadian  

              dollars�察�then only 100 Canadian dollars are declared as taxable monies。 



           Implementing a Tax Engine and Tax Account 



           Implementing a Canadian tax engine means deriving a class from BaseTaxEngine�察�and that  

           means implementing the CreateTaxAccount�┌� method。 The implementation of the Canadian  

           tax engine will be in a new namespace�察�and a good name would be Canada ��as this is in the  

           LibTax project�察�it will have a root namespace of LibTax�察�so LibTax。Canada is the full namespace��。  

           The code will not show the namespace details�察�as they are implied。  

                The implementation is as follows�此�



           Friend Class TaxEngine  

               Inherits BaseTaxEngine 

               Public Overrides Function CreateTaxAccount�┌� As ITaxAccount  

                   Return New TaxAccount�┌� 

               End  Function 


´´´´´´´´´´´´´´´´´´´´´´Page 205´´´´´´´´´´´´´´´´´´´´´´´

                           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 183 



End Class 



     In the implementation of the CreateTaxAccount�┌� method�察�the TaxAccount class is instan

tiated。 TaxAccount is a class that derives from BaseTaxAccount and thus implements the ITaxAccount  

interface。 The implementation of TaxAccount is as follows�此�



Friend Class TaxAccount 

    Inherits BaseTaxAccount 



    Private _province As Province 

    Private _year As Integer 



    Public Overrides Function GetTaxRate��ByVal ine As Double�� As Double 

        If _year = 2008 Then 

            If _province = Province。Ontario Then 

                Return OntarioTax2008。TaxRate��ine�� 

            End If 

        End If 

        Throw New NotSupportedException�─�Year ; & _year & ; Province ; & _ 

            _province & ; not supported;�� 

    End Function 

End Class 



     The purpose of the GetTaxRate�┌� method is to return the applicable tax rate for the given  

amount。 In Canada�察�the tax rate is determined by which province you live in and the year。 The  

calculation in GetTaxRate�┌� has the ability to calculate the taxes for the year 2008 in the Ontario  

province。 Here¨s the skeleton of the OntarioTax2008 class�此�



Public Class OntarioTax2008 

    Public Shared Function TaxRate��ByVal ine As Double�� As Double 

        ' Return the appropriate rate 

    End Function 

End Class 



     Yet there is a problem�察�and it involves the data members _province and _year。 The data  

members are used in the calculation GetTaxRate�┌��察�but they are not assigned。 This is a problem。 



Assigning State When the Interface Cannot 



The problem of the Canadian tax account is a mon one that you will encounter in many  

situations。 The essence of the problem is the need to assign state that is specific to an imple

mentation without violating the intention of the general interface。 

     To illustrate the problem�察�let¨s say that the method GetTaxRate�┌� will include a reference  

to the province and year。 The rewritten  ITaxAccount interface would be as follows�此�



Public Interface ITaxAccount  

    Sub AddDeduction��ByVal deduction As ITaxDeduction�� 

    Sub AddIne��ByVal ine As ITaxIne�� 

    Function GetTaxRate��ByVal ine As Double�察�ByVal province As Province�察�_ 

    ByVal year As Integer�� As Double 


´´´´´´´´´´´´´´´´´´´´´´Page 206´´´´´´´´´´´´´´´´´´´´´´´

184       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 



              ReadOnly Property Deductions�┌� As ITaxDeduction�┌� 

              ReadOnly Property Ine�┌� As ITaxIne�┌� 

           End Interface 



                The bolded code illustrates the added parameters that are used to calculate Canadian taxes。  

          But is this a good solution�拭�No�察�it¨s a particularly bad solution。 The parameters are specific to  

          an implementation�察�and particularly to a Canadian implementation。 

                The parameter year could be justified because most countries do have specific tax rates  

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