嗔秤戻幣�哉膵�云利匈嬉蝕湊蛸賜�塋床四衲���萩晦編報炎嘔囚^泡仟 ̄云利匈��
VB2008貫秘壇欺娼宥(PDF鯉塀哂猟井)-及75何蛍
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何! 泌惚云慕短嗤堋響頼���誅卒亮茂�俊彭堋響��辛聞喘貧圭 "辺茄欺厘議箝誓匂" 孔嬬 才 "紗秘慕禰" 孔嬬��
a matter of experience!the only way to learn is to write code。
Extending the Lottery´Prediction System
In Chapter 10�察�the IProcessor interface was a good first step because it solved the problem at
hand。 The problem was to convert each line of text into another line of text。 However�察�in this
chapter¨s example�察�that interface is not enough。 We need to add two other methods�此�Initialize�┌�
and Destroy�┌�。
We want to find the frequencies of an individual number in the drawn lotteries。 The orig
inal interface method IProcessor。Process�┌� is used to process an individual line of text�察�and
the frequencies can be calculated only after all of the draws have been processed。 Thus�察�we add
Destroy�┌��察�which is called after all of the lines of text have been read。 mon coding convention
´´´´´´´´´´´´´´´´´´´´´´Page 419´´´´´´´´´´´´´´´´´´´´´´´
CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q 397
says that if you have a Destroy�┌� method�察�you should have an Initialize�┌� method that is
called before the lines of text are processed。
Having extra requirements is not a problem and is fairly mon。 But you want to add the
extra requirements without disrupting existing functionality。 After all�察�if some code works�察�you
don¨t want to break it because of additional requirements。 Thus�察�you don¨t want to add the
methods to the IProcessor interface like this�此�
Public Interface IProcessor
Function Initialize�┌� As String
Function Destroy�┌� As String
Function Process��ByVal input As String�� As String
End Interface
This code is a no´no because you are breaking existing functionality。 Any class that imple
ments IProcessor must now implement the methods Initialize�┌� and Destroy�┌��察�even though
those classes don¨t need those methods。
Thus�察�when adding requirements�察�you should not change existing interfaces。 You create
new interfaces and subclass the existing interfaces�察�like this�此�
Public Interface IExtendedProcessor
Inherits IProcessor
Function Destroy�┌� As String
Function Initialize�┌� As String
End Interface
The new interface IExtendedProcessor has the new methods Initialize�┌� and Destroy�┌��察 �
but inherits the method Process�┌�。 The old functionality still has only a single method�察�and the
new functionality is free to implement either interface。
Adding new interfaces and new methods does not mean everything will work as is。 If you
go back and look at the source code from Chapter 10�察�you¨ll see that the IProcessor interface
was used by the Bootstrap class。 So�察�if you want the IExtendedProcessor interface to be recog
nized�察�you must update Bootstrap。 Updating Bootstrap is fine�察�because it does not mean that
IProcessor implementations must be updated ��or�察�at least�察�Bootstrap should not require
that IProcessor implementations be updated��。
The original abbreviated implementation of Bootstrap is as follows�此�
Imports System。IO
Public Module Bootstrap
Public Sub DisplayHelp�┌�
Console。WriteLine�─�You need help�拭�Right now�拭┌�
End Sub
Public Sub Start��ByVal args As String�┌��察�_
ByVal processor As IProcessor��
Dim reader As TextReader = Nothing
Dim writer As TextWriter = Nothing
´´´´´´´´´´´´´´´´´´´´´´Page 420´´´´´´´´´´´´´´´´´´´´´´´
398 CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q
If ��args。Length = 0�� Then
reader = Console。In
writer = Console。Out
ElseIf ��args。Length = 1�� Then
If ��args��0�� = ;´help;�� Then
Bootstrap。DisplayHelp�┌�
Return
End If
reader = File。OpenText��args��0����
writer = Console。Out
End If
' Abbreviated
writer。Write��processor。Process��reader。ReadToEnd�┌�����
End Sub
End Module
In the original implementation�察�the method Process�┌� is called to read an input and write
an output stream。 Since Initialize�┌� and Destroy�┌� should be called before and after the
string is processed�察�the most logical location of each method would be before and after the
processor。Process�┌� method�察�like this�此�
Imports System。IO
Public Module Bootstrap
Public Sub DisplayHelp�┌�
Console。WriteLine�─�You need help�拭�Right now�拭┌�
End Sub
Public Sub Start��ByVal args As String�┌��察�_
ByVal processor As IProcessor��
Dim reader As TextReader = Nothing
Dim writer As TextWriter = Nothing
If ��args。Length = 0�� Then
reader = Console。In
writer = Console。Out
ElseIf ��args。Length = 1�� Then
If ��args��0�� = ;´help;�� Then
Bootstrap。DisplayHelp�┌�
Return
End If
reader = File。OpenText��args��0����
writer = Console。Out
End If
' Abbreviated
If TypeOf processor Is IExtendedProcessor Then
writer。Write�─�_
DirectCast��processor�察�IExtendedProcessor��。Initialize�┌���
End If
´´´´´´´´´´´´´´´´´´´´´´Page 421´´´´´´´´´´´´´´´´´´´´´´´
CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q 399
writer。Write��processor。Process��reader。ReadToEnd�┌�����
If TypeOf processor Is IExtendedProcessor Then
writer。Write��DirectCast��processor�察�IExtendedProcessor��。Destroy�┌���
End If
End Sub
End Module
In the solution�察�the processor interface is tested to see if the interface is an instance of
IExtendedProcessor。 If so�察�then the Initialize�┌� and Destroy�┌� methods can be called。
Extending interfaces and extending those classes that consume the old and new interfaces
at the same time is keeping backward´patibility。 Backward´patibility is an important
concept�察�because it implies you can gradually introduce new functionality into a working
application without breaking old functionality。
Keeping backward´patibility without breaking working functionality is difficult�察�and
there is a point where adding new functionality bees too plicated。 Once you reach this
stage�察�you need to break backward´patibility by doing the following�此�
Public Interface IExtendedProcessor
Function Initialize�┌� As String
Function Destroy�┌� As String
Function Process��ByVal input As String�� As String
End Interface
_
Public Interface IProcessor
Function Process��ByVal input As String�� As String
End Interface
The example will break backward´patibility due to the Obsolete attribute being associated
with the IProcessor interface。 Thus�察�when any class or interface references the IProcessor
interface�察�a pile error results。 The second parameter of Obsolete is true�察�which forces the
piler error。 If you left out that parameter�察�when the interface is referenced�察�a piler
warning�察�rather than a warning�察�is generated。
The IExtendedProcessor interface does not subclass IProcessor and includes the method
Process�┌�。 Thus�察�there are no dependencies between IExtendedProcessor and IProcessor�察�and
all functionality in the application must use IExtendedProcessor rather than IProcessor。
*Note Breaking backward´patibility is a major step�察�because your code cries that some code is broken
and requires alteration。 However�察�sometimes you will need to break code�察�and when you do�察�make sure that
the code cries ^broken� 院�very loud。 Otherwise�察�you might get unexpected errors。
Now that we¨ve updated the Bootstrap class and added the IExtendedProcessor interface�察 �
all of the samples in Chapter 10 will continue to function�察�and we can implement the frequency
solution。
´´´´´´´´´´´´´´´´´´´´´´Page 422´´´´´´´´´´´´´´´´´´´´´´´
400 CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q
Implementing a Frequency Solution
The solution that we want to use is to read in the text�察�convert the text into binary objects�察 �
calculate some statistics�察�and finally write out the text。 The interesting part of this solution is
that pieces of it have already been written。 If you remember in Chapter 10�察�there was a require
ment to convert the lottery draws into binary form。 That code will be borrowed to implement
the statistics functionality。
The statistics console application �─�FrequencyProcessor�� requires an IExtendedProcessor
implementation。 The following is the plete implementation ��note the imports from
Chapter 10¨s example��。
Imports LottoLibrary
Imports ReaderWriter
Imports System
Imports System。Collections。Generic
Imports System。IO
Imports System。Linq
Imports System。Text
Friend Class LottoTicketProcessor
Implements IExtendedProcessor
Private _tickets As List��Of Ticket�� = New List��Of Ticket���┌�
Public Function Destroy�┌� As String Implements IExtendedProcessor。Destroy
Dim builder As New StringBuilder�┌�
Dim c1 As Integer
For c1 = 1 To 46 1
builder。Append�─�Number �──�& c1 & ;�� Found �─┌�
Dim foundCount As Integer = 0
builder。Append�┌┌�foundCount �� FrequencyOfANumber��c1���� & ;��; & ChrW��10������
Next c1
Return builder。ToString�┌�
End Function
Private Function FrequencyOfANumber��ByVal numberToSearch As Integer�� As Integer
Dim query = From ticket In _tickets _
Where ticket。Numbers��0�� = numberToSearch _
Or ticket。Numbers��1�� = numberToSearch _
Or ticket。Numbers��2�� = numberToSearch _
Or ticket。Numbers��3�� = numberToSearch _
Or ticket。Numbers��4�� = numberToSearch _
Or ticket。Numbers��5�� = numberToSearch _
Select ticket。Numbers
Return query。Count�┌�
End Function
´´´´´´´´´´´´´´´´´´´´´´Page 423´´´´´´´´´´´´´´´´´´´´´´´
CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q 401
Public Function Initialize�┌� As String Implements IExtendedProcessor。Initialize
Return ;;
End Function
Public Function Process��ByVal input As String�� As String _
Implements IProcessor。Process
Dim reader As TextReader = New StringReader��input��
Do While reader。Peek ´1
Dim splitUpText As String�┌� = reader。ReadLine。Split��New Char�┌� ��; ;c����
Dim dateSplit As String�┌� = splitUpText��0��。Split��New Char�┌� ��;。;c����
Dim ticket As New Ticket�─�_
New DateTime�─�_
Integer。Parse��dateSplit��0�����察�_
Integer。Parse��dateSplit��1�����察�_
Integer。Parse��dateSplit��2�������察�_
New Integer�┌� �� _
Integer。Parse��splitUpText��1�����察�_
Integer。Parse��splitUpText��2�����察�_
Integer。Parse��splitUpText��3�����察�_
Integer。Parse��splitUpText��4�����察�_
Integer。Parse��splitUpText��5�����察�_
Integer。Parse��splitUpText��6�������察�_
Integer。Parse��splitUpText��7������
_tickets。Add��ticket��
Loop
Return ;;
End Function
End Class
Let¨s examine how the implementation works。
Borrowing Code to Solve Another Problem
The borrowed code is the implementation of the Process�┌� method�察�shown here in abbrevi
ated form�此�
Public Function Process��ByVal input As String�� _
As String Implements IProcessor。Process
Dim reader As TextReader = New StringReader��input��
Do While reader。Peek ´1
Dim splitUpText As String�┌� = reader。ReadLine。Split��New Char�┌� ��; ;c����
Dim dateSplit As String�┌� = splitUpText��0��。Split��New Char�┌� ��;。;c����
Dim ticket As New Ticket�─�_
'。 。 。
Loop
Return ;;
End Function
´´´´´´´´´´´´´´´´´´´´´´Page 424´´´´´´´´´´´´´´´´´´´´´´´
402 CH AP T E R 1 5 * L E A R N I N G A B OU T L I N Q
Other than the new _tickets。Add��ticket�� line�察�the code is identical to the Text2Binary。
Process�┌� implementation。 The bolded code adds the lottery draw to the list of drawn numbers。
Once the tickets have been instantiated�察�they can be added to the list of tickets that will be
queried and searched。
CODE REUSE
The borrowed code demonstrates code reuse through copy and paste。 Realize that code that was used to
process binary objects is now being used in a pletely new context。
The copied and pasted code reuses classes and functionality from another problem context。 You copied
and pasted the functionality to parse and instantiate the Ticket type�察�but reused the Ticket type itself。
When we worked on the code for the Ticket type�察�you probably had no idea that we would reuse the
same code。 In fact�察�even I had no idea that we would reuse the code。 I find this happens a lot in my projects。
So how does this wor
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何!
梁椣戻幣�� 梁心弌傍議揖扮窟燕得胎��傍竃徭失議心隈才凪万弌誌育断蛍�輌臆惨軼僑〃�燕慕得珊辛參資誼持蛍才将刮襲潜��範寔亟圻幹慕得 瓜寡追葎娼得辛參資誼寄楚署衛、持蛍才将刮襲潜填��