按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
The parameter year could be justified because most countries do have specific tax rates
and implementations that are dependent on a year。 Yet the parameter province has no justifi
cation。 Imagine trying to implement a British tax system and needing to specify a province;
when Britain does not collect ine tax at a local level。
A solution might be to redefine the interface as follows:
Public Class Specifics
Public CanadianProvince As Province
Public AmericanState As State
End Class
Public Interface ITaxAccount
Sub AddDeduction(ByVal deduction As ITaxDeduction)
Sub AddIne(ByVal ine As ITaxIne)
Function GetTaxRate(ByVal ine As Double; ByVal year As Integer; _
ByVal specifics As Specifics) As Double
ReadOnly Property Deductions() As ITaxDeduction()
ReadOnly Property Ine() As ITaxIne()
End Interface
This new implementation has a specifics parameter; which is of type Specifics。 The
purpose of Specifics is to define a class that is a hodgepodge of information that is needed to
determine the correct tax rate。 However; the Specifics approach is wrong; for the following
reasons:
o It requires knowing the implementation; which in the case of the interface is a bad idea。
It is like going to a restaurant and saying you would like a waitress with blond hair。
o Even if the type Specifics were acceptable; you would be adding and removing data
members depending on how many tax systems you have implemented。 That is a bad
idea and introduces maintenance issues。
The proposed solutions are not acceptable。 Additionally; there is still the problem of
having to figure out which tax rate to use。
Implementing Ideas with Specifics
To implement a solution; let’s first start by fixing the TaxAccount class。 The modified version
will have some type of functionality that has data members that reference the year and prov
ince。 Here is the modified and correct implementation of TaxAccount:
…………………………………………………………Page 207……………………………………………………………
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 185
Friend Class TaxAccount
Inherits BaseTaxAccount
Private _province As Province
Private _year As Integer
Public Sub New (ByVal province As Province; ByVal year As Integer)
_province = province
_year = year
End Sub
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 fix is to add a constructor that has province and year as parameters。 This sort of fix is
quite mon; in that you don’t change the interfaces; rather you change how the implemen
tations are instantiated。 Remember that when you instantiate a specific implementation; you
know what functionality you want; and thus can give the additional parameters。 Once you are
at the interface level; you should need to use only general ideas。
Now the TaxEngine class needs to be fixed。 TaxEngine is responsible for instantiating
TaxAccount; and thus to instantiate a Canadian TaxAccount; TaxEngine needs additional
parameters; as follows:
Friend Class TaxEngine
Inherits BaseTaxEngine
Public Overrides Function CreateTaxAccount() As ITaxAccount
Return New TaxAccount(Province。Ontario; 2008)
End Function
End Class
In the implementation of CreateTaxAccount(); the province Ontario and year 2008 are
assumed。 Thus; whenever TaxEngine is instantiated; you need to make sure that the person is
in Ontario and paying taxes for the year 2008。 The implementation solves nothing and skirts
the issue of having to figure out how to deal with someone paying their taxes in British Columbia
and the year 2009。
If you look at the implementation of TaxEngine; you will notice it is short。 One obvious solu
tion would be to create a TaxEngine type for each province and each year。 Here are two examples:
…………………………………………………………Page 208……………………………………………………………
186 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
Friend Class Ontario2008TaxEngine
Inherits BaseTaxEngine
Public Overrides Function CreateTaxAccount() As ITaxAccount
Return New TaxAccount(Province。Ontario; 2008)
End Function
End Class
Friend Class BritishColumbia2009TaxEngine
Inherits BaseTaxEngine
Public Overrides Function CreateTaxAccount() As ITaxAccount
Return New TaxAccount(Province。BritishColumbia; 2009)
End Function
End Class
This solution is not that bad; because to be able to instantiate the correct tax engine; you
just need to define a factory that knows which class to instantiate。 But for the problem at hand;
this solution is extremely tedious; as you could end up with hundreds; if not thousands; of
TaxEngine definitions。 You would use the specific implementation approach when you have
fewer than a dozen variations。
The better approach is to