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 Project
git 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)
Scanner
LocalDate
and
OpenJFX Color
; or (class) XML
DocumentBuilderFactory
Comparator
AbstractList
and
AbstractSet
Calendar.Builder
and
Locale.Builder
Observer
and
Observable
(now Deprecated), also
OpenJFX's EventHandler
Reader
s and
Writer
sYou 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