330 likes | 491 Views
Object Oriented Programming. Lecture 7: Algorithm animation using strategy and factory patterns, The Adapter design pattern www.hh.se/staff/jebe/oop2006/main.html. Last lecture. Unit testing Structured testing on units (classes) Reduce complexity by incremental testing on small components
E N D
Object Oriented Programming Lecture 7: Algorithm animation using strategy and factory patterns, The Adapter design pattern www.hh.se/staff/jebe/oop2006/main.html
Last lecture • Unit testing • Structured testing on units (classes) • Reduce complexity by incremental testing on small components • No clutter in the source code • Demonstration of the JUnit tool • Module in Netbeans • Exercise 10: using JUnit
Testing inSoftware development In the Software engineering course Requirements analysis In this OOP Course Design Implementation and unit testing Integration and system testing Maintenance
Template Pattern • Purpose: A generic Class for objects which: • Shares functionality (i.e. same concrete methods in Java) • But also has some method implementations that need to be different (abstract) • The common methods are encapsulated in the template class • We used Template pattern in • the Doublebuffered Animation Applet • the Function Plotter
Structure of the Template pattern Abstract Class Concrete implementations (invariant parts) Abstract methods Subclass extending the template (Concrete class) Implements the hookMethods
Strategy pattern • Purpose: An abstraction to decouple algorithms from its host • Force provision of a set of required services (methods) but with different implementations • With strategy pattern we can implement contractually compatible classes with different algorithms • A useful methodolgy to dynamically swap algorithms in a program
Design Pattern: Strategy The plotter The abstract strategy Concrete implementations
Animation of Sorting Algorithms • Applet to visualize execution of sorting algorithms • It should be easy to adapt for • different sort algorithms • different displays • Demonstrates usage of Factory, Strategy and Observer - Observable patterns
Sorting Algorithms • Input to the Algorithm Sorter: an array of Integers • Choosing different sorting algorithms executing with different complexities • Bubble Sort O(n2) • Quick Sort O(n*log n) • Insertion Sort O(n2) • ... • The framework should adapt to different algorithms and different display strategies
Generic Algorithm Animation – Design Issues • Algorithm Abstraction? • Problem: How can we easily change between different algorithms? • Integration with Animation during sorting? • Problem: The screen should be redrawn after each iterative step, running the algorithm • Display Abstractions? • Problem: We will also need a modular way to hook different graphical displays
Starting the design of the Algorithm Animator • Two design pattern candidates: • Template – Not flexible since we want to assign any sorting algorithm after compile time (recall the function multiplotter from last lecture) • Strategy – More flexible since we can decouple the sort algorithms from the animator • We will use strategy pattern to separate the algorithm from animator
Design Pattern: Strategy The Strategy interface So we can render between each sort iteration! Concrete Sort algorithms
The Sorting Abstraction • Has an abstract sort method • Called by the Animator to start sorting • Issue: How do we render the animation between each swap during the sort? • Solution: We implement a pause() function! • Will pause the sorting and render after each swap during the sorting process • Since all sorting algorithms involve swapping of two values • Makes sense to factor swap into the sorting abstraction • Issue: How do we render the image after each swap? • Use a Animator reference to call: animator.pause(); • We will use the Observer-Observable pattern!
The sorting abstraction public abstract class SortAlgorithm extends java.util.Observable { abstract void sort(int a[]); protected void pause(){ setChanged(); notifyObservers(); } protected static void swap(int a[], int i, int j) { int T; T = a[i]; a[i] = a[j]; a[j] = T; } }
A concrete sorting algorithm class BubbleSortAlgorithm extends SortAlgorithm { void sort(int a[]) { for (int i = a.length; --i>=0; ) for (int j = 0; j<i; j++) { if (a[j] > a[j+1]) swap(a, j, j+1); pause(); } } }
The algorithm animator • The AlgorithmAnimator template • abstract method for initAnimator(); • A an applet • Implements Runnable and Observer • A thread controls frame delay • Performs animation of an abstract SortAlgorithm • The animation is controlled by • Thread to handle frame delay • The Observer Observable pattern for drawing synchronisation
A Bubble sorter using the AlgorithmAnimator template public class BubbleSorter extends AlgorithmAnimator { protected void initAnimator(){ theAlgorithm = new BubbleSortAlgorithm(); } }
How can we improve the design? • The different sort algorithms are strongly coupled to the specific Animator • We want the sorting algorithms be easily interchangable • Loading algorithms at startup • We want the client (Algorithm Animator) be unaware of the concrete algorithms
Improving our design using the Factory Design Pattern • We can separate the creation of algorithms in a separate class • We call this class a Factory and it produces products (Sort Algorithms) of a certain type (Sorting Abstraction) • Can be abstractly ”hooked” to the animator • The concrete algorithms will be coupled to the Algorithm Factory instead of the Algorithm Animator
The Factory Design Pattern Using Strategy to decouple the algorithms The concrete Factory
StaticAlgoFactory • Input: the name of a sorting algorithm (String) • Output: A concrete instance of the abstract SortAlgorithm (a product) • The Contractual Interface: • abstract makeSortAlgorithm(String algName){...} • Must be defined by every concrete AlgoFactory • Binds the actual algorithm to the animator
The Strategy abstraction of Factory and a concrete implementation public interface SortAlgorithmFactory { SortAlgorithm makeSortAlgorithm(String name); }
A concrete Algorithm Factory public class StaticAlgoFactory implements SortAlgorithmFactory { public SortAlgorithm makeSortAlgorithm(String name) { if ("BubbleSort".equals(name)) return new BubbleSortAlgorithm(); else if ("QuickSort".equals(name)) return new QuickSortAlgorithm(); else return new BubbleSortAlgorithm(); } }
Using the improved AlgorithmAnimator import java.awt.*; public class Sort extends AlgorithmAnimator { protected void initAnimator() { String algoName = getParameter("alg"); SortAlgorithmFactory factory = new StaticAlgoFactory(); theAlgorithm = factory.makeSortAlgorithm(algoName); } }
Invoking the AlgorithmAnimation applet <applet code=Sort.class width=100 height=100> <param name = alg value = QuickSort> </applet>
Further improvement: Decoupling the SortDisplay • public int getArraySize() • method to provide the arraysize so we know the maximum bars we can draw and animate using this display • public void Display(int[] a, Graphics g, Dimension d) • The abstract drawing method, to be called by paint • To be implemented as exercise!
New Design Pattern: Adapter • A design pattern that can be used to: • reuse classes without modifying the code, instead we convert the interface! • narrow interfaces when just needing a small subset of the methods
Simple example: Narrowing of thye MouseListener with MouseAdapter • Some classes have an implementation which does not ”fit” the requirements • Or we might only need few of the availabe methods • Ex. listening for mouse actions • MouseAdapter is a class implementing the MouseListener interface • The adapter defines all MouseListener methods empty (No action as default) • By extending the MouseAdapter we only have to override the methods we need in the mouse listener interface
The MouseListener interface void mouseClicked(MouseEvent e); Invoked when the mouse button has been clicked (pressed and released) on a component. void mouseEntered(MouseEvent e); Invoked when the mouse enters a component. void mouseExited(MouseEvent e); Invoked when the mouse exits a component. void mousePressed(MouseEvent e); Invoked when a mouse button has been pressed on a component. void mouseReleased(MouseEvent e); Invoked when a mouse button has been released on a component.
The MouseAdapter void mouseClicked(MouseEvent e){/* no action */} Invoked when the mouse has been clicked on a component. void mouseEntered(MouseEvent e) {/* no action */} Invoked when the mouse enters a component. void mouseExited(MouseEvent e) {/* no action */} Invoked when the mouse exits a component. void mousePressed(MouseEvent e) {/* no action */} Invoked when a mouse button has been pressed on a component. void mouseReleased(MouseEvent e) {/* no action */} Invoked when a mouse button has been released on a component.
A Simple MouseClick listener Public MouseClick extends MouseAdapter{ void mouseClicked(MouseEvent e){ System.out.println(”Disco!”); } /** * Other MouseListener methods can be omitted **/ }