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