390 likes | 546 Views
Computer Science 340 Software Design & Testing. Software Reuse. The quest for software reuse. Reuse is an important goal of software design Software developers are notorious for “reinventing the wheel” by repeating work that has been done many times in the past.
E N D
Computer Science 340Software Design & Testing Software Reuse
The quest for software reuse Reuse is an important goal of software design Software developers are notorious for “reinventing the wheel” by repeating work that has been done many times in the past. For years people have touted the virtue of the reuse achieved by hardware engineers, who frequently use off-the-shelf (OTS) components in their designs. The hope has been that similar reuse could be achieved through properly designed software “components”.
Benefits of reuse • Timeliness • Decreased maintenance effort • Reliability • Efficiency • Consistency • Lower cost • Less redundancy in the work
Examples of successful reuse • OS APIs are used by all programs that run on the OS (e.g., the Windows scroll bar) • Built-in libraries provided by programming languages are reused by all programs written in that language (e.g., C++ STL) • Third-party libraries that perform generally-useful functions, such as: OpenSSL (secure communication), zlib (compression), boost, Qt (useful C++ libraries) • Application Frameworks: GUI Frameworks (WPF), Web App Frameworks (RoR), Enterprise App Frameworks (Java EE), etc.
Forces operating against reuse • At first glance, the lack of reuse in software makes little sense, but there are reasons for it. • What conditions must exist to make a class reusable? • Generality (customizable to the present need) • Performant (general without sacrificing performance) • Available across programming languages and operating systems • Easily obtainable (inexpensive or free, reasonable licensing, downloadable on web) • Well documented • Well supported and maintained • Source code available • Awareness (if I don’t know about it, I can’t use it) • Maturity and Humility (overcome NIH syndrome and the urge to do it myself) • If all relevant conditions are satisfied, reuse will often occur.
Forms of reuse • Binaries • Source code • Design patterns • Specifications • Requirements, Functional, Design • People • Knowledge and experience
Techniques for reusing / customizing class behavior • Composition • Class A “uses” Class B to do its work • Reuse a class by creating an object and calling methods on it • Create “wrappers” to add additional functionality, if needed • The most common form of code reuse (we do this all the time) • Inheritance • Inherit superclass functionality • Customize superclass behavior by overriding its methods • Totally replace or augment with pre/post processing • Extend superclass functionality by adding new variables/methods • Parameterization • Design a class so its behavior/functionality can be customized to the current application • Generic Types • E.g., C++ templates, Java and C# generics (e.g., ArrayList<Device>) • Provide “options” that can be customized by the client through constructor parameters, method parameters, or properties • E.g., a GUI ListBox class might provide the following sorting options (None, Ascending, Descending)
Adapter Pattern • You have a class that does what you need, but the interface it supports is not the interface expected by the rest of the application. You can write an "adapter" class to translate between the interface expected by clients, and the interface provided by the class. • Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interface
Adapter Pattern • Why not just modify the class to support the interface required by its clients? • 1) You don't have the source code for the third-party class • 2) You have the source code, but you don't want to couple the class to the interface expected by clients (i.e., in general there is a different interface that you prefer for the class, but for integration purposes you must support the mandated interface).
public class AddressBookTableAdapter implements TableModel { AddressBookab; public AddressBookTableAdapter( AddressBookab ){ this.ab = ab; } public intgetRowCount() { return ab.getSize(); } public intgetColumnCount() { return 3; } public String getColumnName(intcolumnIndex) { switch (columnIndex) { case 0: return "First Name”; case 1: return "Last Name”; case 2: return "Email Address"; } } public Object getValueAt(introwIndex, intcolumnIndex) { Person p = ab.getPerson(rowIndex); switch (columnIndex) { case 0: return p.getFirstName(); case 1: return p.getLastName(); case 2: return p.getEmailAddress(); } } ... } public class AddressBook{ List personList; public intgetSize() {...} public intaddPerson(Person p) {...} public Person getPerson(int index) {...} ... } public interface TableModel{ public intgetRowCount(); public intgetColumnCount(); public String getColumnName(intcolumnIndex); public Object getValueAt(introwIndex, intcolumnIndex); … }
Decorator Pattern • Sometimes we need to be able to add functionality to an object in a flexible and dynamic way • Don’t want to change the base functionality, just add to it • Window Window with scrollbars • Can be done with inheritance and composition
Decorator with Inheritance class A { void run() { System.out.println("A.run"); } } class B extends A { void run() { System.out.println("B.run pre-processing"); super.run(); System.out.println("B.run post-processing"); } } class C extends B { void run() { System.out.println("C.run pre-processing"); super.run(); System.out.println("C.run post-processing"); } } // // Client // A obj = new C(); obj.run();
Decorator with Composition interface Runner { void run(); } class A implements Runner { void run() { System.out.println("A.run"); } } class B implements Runner { Runner delegate; B(Runner delegate) { this.delegate = delegate; } void run() { System.out.println("B.run pre-processing"); delegate.run(); System.out.println("B.run post-processing"); } }
Decorator with Composition cont. class C implements Runner { Runner delegate; C(Runner delegate) { this.delegate = delegate; } void run() { System.out.println("C.run pre-processing"); delegate.run(); System.out.println("C.run post-processing"); } } // // Client // Runner obj = new C(new B(newA())); obj.run();
Decorator : augment a class’s functionality using composition
// the Window abstract class publicabstractclass Window { publicabstractvoid draw(); // draws the Window publicabstract String getDescription(); // returns a description of the Window } // extension of a simple Window without any scrollbars classSimpleWindowextends Window { publicvoid draw() { // drawwindow } public String getDescription() { return "simplewindow"; } }
// abstract decorator class - note that it extends Window abstractclassWindowDecoratorextends Window { protected Window decoratedWindow; // the Window being decorated publicWindowDecorator (Window decoratedWindow) { this.decoratedWindow = decoratedWindow; } publicvoid draw() { decoratedWindow.draw(); //delegation } public String getDescription() { returndecoratedWindow.getDescription(); //delegation } }
// the first concrete decorator which adds vertical scrollbar functionality classVerticalScrollBarDecoratorextendsWindowDecorator { publicVerticalScrollBarDecorator (Window decoratedWindow) { super(decoratedWindow); } @Override publicvoid draw() { super.draw(); drawVerticalScrollBar(); } privatevoiddrawVerticalScrollBar() { // draw the verticalscrollbar } @Override public String getDescription() { returnsuper.getDescription() + ", includingverticalscrollbars"; } }
// the second concrete decorator which adds horizontal scrollbar functionality classHorizontalScrollBarDecoratorextendsWindowDecorator { publicHorizontalScrollBarDecorator (Window decoratedWindow) { super(decoratedWindow); } @Override publicvoid draw() { super.draw(); drawHorizontalScrollBar(); } privatevoiddrawHorizontalScrollBar() { // draw the horizontalscrollbar } @Override public String getDescription() { returnsuper.getDescription() + ", includinghorizontalscrollbars"; } }
publicclassDecoratedWindowTest { publicstaticvoid main(String[] args) { // create a decorated Window with horizontal and vertical scrollbars Window decoratedWindow = newHorizontalScrollBarDecorator ( newVerticalScrollBarDecorator(newSimpleWindow())); // print the Window's description System.out.println(decoratedWindow.getDescription()); } }
Examples of reusable code • Reusable Array class • C++ • Java • Reusable Manager interface • Java • Reusable InputStream decorators • Java
Examples of reusable code • Generic functions/methods • C++ maxfunction template • Java arrayToCollectiongeneric method
Strategy pattern : customize a class’s functionality with plug-in algorithms • Class C implements some generally useful functionality • C does most of the work, but some aspects of its behavior can be customized by clients • Clients customize C’s behavior by passing in “algorithms” that are invoked by C at appropriate times • The “algorithms” passed in by clients are called “strategies” • C invokes the client-provided strategies as needed to perform its work • A “strategy” is an object that implements an algorithm • This is an alternative to using inheritance to customize a class’s behavior
Strategy pattern : customize a class’s functionality with plug-in algorithms
Strategy pattern : customize a class’s functionality with plug-in algorithms • The following examples of reusable code use the Strategy pattern
Strategy pattern : customize a class’s functionality with plug-in algorithms • Examples: • Input validation • Sorter
Examples of reusable code • Sort(Person[]); • How could we make this sorting algorithm more reusable?
Examples of reusable code • Sort(Person[]); • How could we make this sorting algorithm more reusable? • Sort(Comparable[]) • interface Comparable { int compareTo(Object o); }
Examples of reusable code • Sort(Person[]); • How could we make this sorting algorithm more reusable? • Sort(Comparable[]) • interface Comparable { int compareTo(Object o); } • Sort(Object[], Comparator) • interface Comparator { int compare(Object o1, Object o2); }
Examples of reusable code • Sort(Person[]); • How could we make this sorting algorithm more reusable? • Sort(Comparable[]) • interface Comparable { int compareTo(Object o); } • Sort(Object[], Comparator) • interface Comparator { int compare(Object o1, Object o2); } • Anybody remember qsort from 240? • Very reusable
Examples of reusable code • Java TreeSet generic class • Code • Instantiating TreeSet<SomeClass> requires that SomeClass implement the Comparableinterface so the tree can sort the elements • What if SomeClass doesn’t implement Comparable? • Or, what if we need a sort order different from the one SomeClass implements? • Can we still use TreeSet? • Yes. TreeSet has a constructor that lets you pass in a comparator object that defines the sort order to be used. • public TreeSet(Comparator<? super E> c)
Examples of reusable code • C++ map class template • template <typename Key, typename Value, typename Comparator, typename Allocator >class map { … } • Key and value types can be specified (of course) • By default, uses Key’s < operator to sort • If you don’t like that, Comparator class can be specified to customize sorting • Overloads bool operator ()(Key a, Key b) • Memory allocator class can be specified to customize memory management • Implements a standard memory allocator interface (allocate block, deallocate block, etc.)
Examples of reusable code • CLoggerclass • Logging class that provides customizable thread synchronization behavior • If multiple threads will be logging messages, thread synchronization will be needed • If only one thread will be logging messages, no thread synchronization is needed • In order to avoid unnecessary overhead due to thread synchronization, the CLogger class allows the client to specify the desired thread synchronization behavior
Examples of reusable code • EmailClientclass • EmailClient.send method supports a generic method for acquiring user credentials (user name & password) • This allows the EmailClient class to be reused in many kinds of applications