| CompSci 308 Spring 2023 |
Advanced Software Design and Implementation |
This exercise is intended to help you to practice using Design Patterns to help organize and justify your design choices as well as direct your Refactoring.
At the end of lab, use Gitlab's Merge Request from your forked repository's master branch back to the original organization repository's master branch to submit your group's discussion summary and refactored code.
Make sure the Title of your Merge Request is of the form "lab_patterns - everyone's NetIDs".
In your pairs within project team, work together using Pair Programming, with separate cloned repositories or use IntelliJ's Code With Me feature, to complete the following activities today:
lab_patterns into their own repository to allow pushing your group's changes
Project Information -> Members (in the upper left corner) to add your partner so both people in the group can access the same repositoryMaintainer role in the project and choose Add to Projectgit clone to copy the one forked repository to their individual machines so they can work on their own separate copiesOpen the cloned folder to create a new project on their personal machineTechnically, you already know how to implement Design Patterns since they use the basic Java skills and the SOLID design principles you have learned and practiced throughout the semester. In fact, you have likely already implemented at least one Design Pattern in your code without knowing there was a "name for it". Thus, Design Patterns are really just a good shorthand for referring to how a group of classes work together to achieve a design goal as well as describing the implementation's design trade-offs since just about any abstraction you create has a design goal. Still, learning explicitly about Design Patterns can often open up your thinking about different ways to solve a design problem you are having — even though, as you can see from the examples below, sometimes the final implementation can seem very simplistic.
Also note that Java was created around the same time, so it was heavily influenced by them and, in fact, used many of their names directly for interfaces and classes (making it very confusing since patterns are intended to describe how multiple classes interact rather than one single class or abstraction).
Identify the methods of these Java classes that represent their respective Pattern and compare them to its standard description:
Iterator and
Iterable; or (built into the class)
ScannerLocalDate and
OpenJFX Color; or (class) XML
DocumentBuilderFactoryComparatorAbstractList and
AbstractSetCalendar.Builder and
Locale.BuilderObserver and
Observable (now Deprecated), also
OpenJFX's EventHandlerReaders and
WritersYou can also look at their implementation (such as this Template Method or this Builder class).
In your discussion summary, if there is something you like or dislike or something your learned about design during the discussion, make sure to back it up with a specific example.
Using the code in the project's bins package, complete the following refactoring to implement the Strategy pattern:
Bins class, using Lambdas to easily create the subclasses
fitDisksAndPrint() method so that it takes a third parameter of type Consumer<List<Integer>> and replace the entire chain of conditionals with a single call to the parameter's accept() method, passing the correct list variable.main() method, change the calls to the fitDisksAndPrint() method to provide this third parameter using Lambdas rather than writing out the complete code to declare and instantiate class instances that implement Consumer<List<Integer>>. Two of the Lambdas will transform the list parameter in some way (e.g., sort, shuffle, or reverse) and one will be empty (i.e., do nothing). ->, syntax.Map<String, Consumer<List<Integer>>>, i.e., the description and its associated action.main() method.main() method, replace the three calls to the fitDisksAndPrint() method with a loop using the constant Map to supply the parameter values for each call instead of the current constants and actionsUsing the code in the project's game package, complete the following refactoring to implement the Factory pattern
BetFactory class that manages possible Bet subclasses and returns the one chosen by the user so the Game no longer has to manage that responsibilitypromptForBet() method from the Game class to the new BetFactory classpublic method named makeBet(), that take no parameters and return a Bet superclass, and will be called from the Game class (instead of promptForBet())Bet subclasses to use reflection (note, the available bets will still be hardcoded)List<Bet> to a List<String>, where the strings represent the complete name of each Bet subclass (i.e., the class's package as well as its name). makeBetFromString() that gets a Class object representing the Bet subclass named in the given string using the forName() method, then gets its Constructor object, and calls the newInstance() method (and catches its many exceptions) instead of using the instance directly in the previous list.Bet subclass or create some logic to provide the description and odds for each subclass — whichever makes more sense for you to practice for your project.BetFactory constructor, read it using a ResourceBundle object to determine which subclasses are possible to create so that nothing is hardcodedList instance variable(s).Bet subclass name (for the default constructor) or the complete Bet subclass name to its odds and description, on one line separated by a comma for easy parsing by your program (for the two argument constructor) — whichever makes more sense for you to practice for your project.Using the code in the project's matrix package, complete the following methods to implement the Iterator pattern
MatrixIterator by implementing Java's expected Iterator methods correctly (you may introduce any instance variables you want to keep track of the current element to return)
hasNext() method to return true only if there is at least one more element availablenext() method to return the next sequential element in the matrix (i.e., going to the next row when necessary)main() method of the Main class to verify your implementation basically works