nameand a list of
participants. Students have attributes such as an identifying
satScore(see SAT score).
Consolehere to keep things simple) is a task that should be delegated to some sort of
Viewcomponent. Let's create a
CourseViewcomponent and have it print out sample data through a
CourseViewclass and have it sort the participants by their
lastName(in ascending order) before printing out the results:
Array.sort([compareFunction])function for sorting, which is part of the ECMAScript Language Specficiation 5.1. It accepts as an argument a universal
compareFunctionthat defines the general sort order and that itself accepts two elements
Band returns a negative number if
A < B(i.e.
B), 0 if
A == B(i.e.
Bequal) and a positive number if
A > B(i.e.
B). In our case, such comparing is delegated to the
compareByLastNameAscending(a: Student, b: Student): numbermethod, which does exactly as it says: It compares the
Students by their
lastNamein ascending order.
sortByLastName: booleanto the
CourseViewclass, which will act as a switch for the sorting criterion to apply. We will also add a new compare method
private compareByScore(a: Student, b: Student): numberto compare students by their
scores. In our
printParticipants()method we will then have to pick the proper compare method ( as selected by our switch) and pass it to the
falseand thus have our participants sorted by
CourseViewclass already beings to look bloated. If we keep adding more features, our class will soon burst at the seams. For now, it looks as though we might get away with this convoluted code arrangement.
nr. You're sensing a pattern here. We cannot just keep adding new switches and compare methods to accompany every new sorting feature. The
sortByLastNameswitch is already a bad choice as it doesn't tell us anything about what happens if it is
false. If we were to add another switch, our code base would disintegrate completely.
CourseViewclass is doing too many things at once and thus violating the Single Responsibility Principle (SRP). Now that you come to think about it, the class also doesn't adhere to the Open-Closed Principle (OCP): We cannot just add another sorting criterion without modifying the existing class structure. Our current code is definitely not closed to modification as the OCP demands.
CourseViewclass could then receive a property that references the current sorting strategy.
SortingStrategy. It could be made an abstract class and would only handle the sorting logic according to an internal compare method, the implementation of which it would delegate to its sub types. Our players and their relationships could then look something like this:
Array.slice(0)) and operate on this one, so as not to have any permanent side-effects (operating on the original array would have it changed every time we call the sort method).
LastNameAscendingSortingStrategy: sorting by
StudentNrAscendingSortingStrategy: sorting by
SatScoreDescendingSortingStrategy: sorting by
CourseViewclass would receive a
sortingStrategyproperty, which would act as the new switch to give the client the ability to parameterize the desired sorting strategy. Also, the
CourseViewwould have to sort the list of participants according the the strategy currently assigned.
compareStudents(a: Student, b: Student): numbermethod in our base class
SortingStrategy. The number returned really isn't up to any good. All it does is tell us how to sort two
a < b(returns
-1or any negative number),
a == b(returns
a > b(returns
1or any positive number). Let's try to make this a bit less subtle and more explicit. After all, TypeScript allows us to define number-based
enums. We could define our own
enumtype and have it return those numbers behind more expressive names:
compareStudents(...)method would then have to return the new
ComparisonResultenum type instead of a
numberdirectly (here only exemplified using the