按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
method; implying that DepthFirstSearch must be instantiated before we can call FindRoute()。
We should modify the test again as follows:
Public Sub TestSearch()
Dim cls As DepthFirstSearch = New DepthFirstSearch()
cls。FindRoute(〃Montreal〃; 〃Seattle〃)
End Sub
To execute the method FindRoute(); we need to create a DepthFirstSearch object; allowing
multiple users to perform searches without getting state mixed up。 At this point; we could pat
ourselves on the back and think that we have written a good test that requires a class
implementation。
The Problem of Magic Data
Our test is not yet plete; because we don’t have access to the route found by the algorithm;
but that will be explained in a moment。
In the implementation of DepthFirstSearch; a reference to the data structure is necessary。
The search algorithm needs to know which tree to navigate。 One way to implement a reference
to the tree is to directly reference the shared data Node。RootNodes。 An implementation of
DepthFirstSearch would be as follows:
…………………………………………………………Page 122……………………………………………………………
100 CH AP T E R 4 ■ L E A R N IN G AB OU T D AT A S TR U CT U R E S; DE CI SI ON S; A N D L O OP S
Public Class DepthFirstSearch
Public Sub FindRoute(ByVal start As String; ByVal finish As String)
Dim startNodes As Node() = Node。RootNodes
End Sub
End Class
This example declares a variable called startNodes; which represents the starting point
and root of the tree as shown in Figure 4…2。 The root of the tree is based on the data member
Node。RootNodes; and this assignment is called a magic type assignment。 A magic type is formed
when you call a method; and magically; it happens to know how to reference data; even though
you never instructed the type。 In the case of DepthFirstSearch; the magic is the ability of
FindRoute() to know to reference the correct data member RootNodes。
The assumption is bad because it couples the data member RootNodes to the method
FindRoute()。 Imagine if the developer of the Node class later decides to add functionality to load
the tree from a file on the hard disk。 So that FindRoute() is not broken; the developer would
need to explicitly copy the hard…disk…loaded tree to the data member RootNodes。
Or what if two different users wanted to create two different flight trees? Node。RootNodes is
a shared resource; and thus can process only a single flight tree。 The developer of Node might
alter RootNodes; and thus FindRoute() would behave erratically。
When you have a case of magic data; whatever data is magic needs to be passed to the type
via a constructor or other method。 So the test for the flight route would change to the following:
Public Sub TestSearch()
Dim cls As DepthFirstSearch= _
New DepthFirstSearch(Node。RootNodes)
cls。FindRoute(〃Montreal〃; 〃Seattle〃)
End Sub
As the root tree node is required; we change the constructor to require that a caller pass in the
root tree node。 The test code still uses the shared data member RootNodes; but DepthFirstSearch
does not need to know where to find the tree。 If the Node developer were to alter the behavior of
the data member RootNodes; then only the constructor code to DepthFirstSearch would need
altering; not the FindRoute() method。 Thus; Node and DepthFirstSearch are properly decoupled
from each other。
Getting the Found Route
Once you have called the FindRoute() method; you expect an answer。 Because the route could
involve multiple cities; the found route is stored in an array of Node elements。 In programmatic
terms; there are two ways of retrieving the array of Nodes。 The first is a return value; like this:
Public Sub TestSearch()
Dim cls As DepthFirstSearch = New DepthFirstSearch(Node。RootNodes)
Dim foundRoute As Node() = cls。FindRoute(〃Montreal〃; 〃Seattle〃)
End Sub
The bold code shows the assignment of the return value to the variable foundRoute。
…………………………………………………………Page 123……………………………………………………………
CH AP T E R 4 ■ L E A R N I N G A B OU T D AT A S TR U CT U R E S; DE CI SI ON S; A N D L O OP S 101
The second approach is for the FindRoute() method to store the result in an internal data
member。 The following example assumes that the FindRoute() method stores the result in a
data member named FoundRoute:
Public Sub TestSearch()
Dim cls As DepthfirstSearch = New DepthFirstSearch(Node。RootNodes)
cls。FindRoute(〃Montreal〃; 〃Seattle〃)
Dim foundRoute As Node() = cls。FoundRoute
End Sub
Each approach seems acceptable; and you are not sure which to use。 When you have a
choice like this; you need to make a decision。 The safest way to make a decision is to write tests
and see if there are any problems with either approach。
In the example of calculating a single route; either approach is fine。 But let’s look at the
code when multiple routes are being searched。 First; consider the code where the found path
is a return parameter value:
Public Sub TestSearch()
Dim cls As DepthFirstSearch = New DepthFirstSearch(Node。RootNodes)
Dim foundRoute1 As Node() = cls。FindRoute(〃Montreal〃; 〃Seattle〃)
Dim foundRoute2 As Node() = cls。FindRoute(〃New York〃; 〃Seattle〃)
End Sub
Now take a look at the code that uses the data member:
Public Sub TestSearch()
Dim cls As DepthFirstSearch = New DepthFirstSearch(Node。RootNodes)