按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
on
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