280 likes | 493 Views
Systems Analysis & Design Methods. VIII More OOD issues: Patterns & Testing. Books/links:. Design Patterns Gamma, Helm, Johnson, Vlissides (GOF). Contents. Design Patterns What are design patterns ? Why learn patterns ? Reducing the impact of change Some patterns See next slide
E N D
Systems Analysis & Design Methods VIII More OOD issues: Patterns & Testing
Books/links: • Design Patterns • Gamma, Helm, Johnson, Vlissides (GOF) More OOD issues: Patterns & Testing
Contents • Design Patterns • What are design patterns ? • Why learn patterns ? • Reducing the impact of change • Some patterns See next slide • Automatic Testing an example More OOD issues: Patterns & Testing
Some design patterns • Creational • Factory Method • Singleton • Structural • Composite • Façade • Behavioral • Command • State (covered here) • Template (covered here) A detailed coverage of patterns will be given by Patrick Fox in the 3d year More OOD issues: Patterns & Testing
What are design patterns ? • =Standard solutions for standard problems. • On ‘design’ level: reusable design, not reusable code. • It is about slightly bigger designs than described in OO first rules & OOD principles. • ‘design patterns’ have gained attention because of the book by the ‘gang of 4’ GOF (see slide 2) More OOD issues: Patterns & Testing
Why learn patterns ? • Many problems about software modification have a lot in common . They have to do with a change that has an impact on the entire system, a change that is simply too big. Design patterns can help you avoid these problems. • If you already know some patterns, you loose less time looking for a solution. • A lot of patterns have been discovered a long time ago by many developers independent of each other. But by giving it a single name, communications about patterns are raised to a higher level. More OOD issues: Patterns & Testing
Reducing the impact of change • Problem: When creating an object ourselves (with ‘new’), we are dependent of a concrete class. If this class has to change (e.g. its name), we might have to change our code too. (example of Dependency Inversion) pattern/solution: build a Factory Method • Problem: We already know how to make a new method by calling previously developed more elementary methods (see first rules: common code). But the other way around also exists : You have to add a method which has the same structure as an existing one, but your new method needs other elementary methods. How can we use our previous work (without copy pasting) ? pattern/solution: design a Template Method More OOD issues: Patterns & Testing
Reducing the impact of change • Problem: In a previous project we have build classes of which we would like to use about 10% . Unfortunately the classes have lots of public methods with lots of parameters we don’t care about. Also, if we want to use one class we have to know about hundreds of other classes. We are not allowed to touch the existing classes to improve the design pattern/solution: put up a Façade Warning: Don’t be a pattern bigot. Use a pattern only when you experience the problem it tries to solve !!! More OOD issues: Patterns & Testing
State-pattern • A changeable property is represented by an attribute (see first rules). We cannot use a subclass, because an object cannot change its class. But, with a trick, we can exploit the mechanisms of subclassing and polymorphism. The trick is ‘the state-pattern’. • With an example we show how we can avoid if-tests like we always do when using polymorphism. More OOD issues: Patterns & Testing
State: the problem public double getIncTaxPerc(){ if ( maritalState == MARRIED ) return NORM_PERC - DEDUCTION; else return NORM_PERC; } Employee -maritalState : int +getMaritalState() : int +getIncTaxPerc() : double +getPension() : double More OOD issues: Patterns & Testing
State: the problem • The problem with the code in de previous slide is this: If a new marital state is added, (widower), then, all existing similar if-tests have to be searched and changed, thereby altering many classes and maybe forgetting some parts. More OOD issues: Patterns & Testing
State: the solution <<abstract>> Employee public double getTaxPerc(){ return maritalState.getTaxPerc(); } // note: In some cases we have // to pass ‘this’, like in : //return burgStand.getBelPerc(this); MaritalState -maritalState : MaritalState +getTaxPerc() : double +getPension() : double +get MaritalState() : MaritalState +getTaxPerc() : double +getPension() : double Bachelor Married +getTaxPerc() : double +getTaxPerc() : double +getPension() : double +getPension() : double public double getTaxPerc(){ return NORM_PERC; } public double getTaxPerc(){ return NORM_PERC - DEDUCTION; } More OOD issues: Patterns & Testing
Template Method-pattern • It often happens that the structure (the template) of 2 methods is the same is, but that the more elementary operations differ. For example, the following code might exist in different places in a sourcefile: we loop through al list, thereby using the same if-tests. • In the example we show, how we can change the elementary methods without touching the template-method. More OOD issues: Patterns & Testing
Template Method: the problem public void increment(){ for(int i = 0 ; i < list.size(); i++) …; // increment every element } public void decrement(){ for(int i = 0 ; i < list.size(); i++) …; // decrement every element } public void print(){ for(int i = 0 ; i < list.size(); i++) System.out.println( list.get(i) ); } IntegerList -list : List +increment() +decrement() +print() More OOD issues: Patterns & Testing
Template Method: the problem • The problem with the code in de previous slide is this: The code is not capable of factoring out the common part, which in this case is: the for-loop . Every method which runs through the list, needs to rewrite the for-loop. The problem deteriorates, if extra conditional code would have to be repeated too. • The structure remains the same, • The elementary operations differ (increment, decrement,, print, …) More OOD issues: Patterns & Testing
Template Method: the solution <<abstract>> public void execute(){ for(int i = 0 ; i < list.size(); i++) operation(i); } IntegerList Iteration -list : List -list : List +execute() <<abstract>> #operation(int i) +increment() +decrement() +print() Print Increment Decrement #operation(int i) #operation(int i) #operation(int i) public void print(){ (new Print(list)).execute(); } protected void operation(int i){ System.out.println(list.get(i)); } More OOD issues: Patterns & Testing
Automatic Testingan example • The Class Diagram • Start writing the test class. • Repeat until all tests are written and passed • Write a test in the test class. • Write part of the tested class, enough for the test class and the tested class to survive compilation. • Write the part of the tested class that makes it pass the test • Write another test. More OOD issues: Patterns & Testing
Automatic Testingan example • Write the test before you write what is tested. • Advantages of automated tests: • Code requirements are clearly specified: just look at the tests. • Testing whether requirements are met, is easy: just run the tests. • Possible damage, caused by adapting code, is found quickly: just run the tests. More OOD issues: Patterns & Testing
Automatic Testingan example Directory structure: • c:\ • javaoef • test • Test.java (serves as abstract superclass to your own test classes) • invoiceApp • Invoice.java (in a minute) • InvoiceLine.java • invoiceAppTest • InvoiceAppTest.java (concrete testclass) More OOD issues: Patterns & Testing
Class Model: Integration with ‘test environment’ More OOD issues: Patterns & Testing
InvoiceAppTest.java package invoiceAppTest; import java.util.Date; import test.Test; import invoiceApp.*; public class InvoiceAppTest extends Test{ public static void main(String[] args){ (new InvoiceAppTest()).run(); } protected void compareAll(){ // Tests go here } } More OOD issues: Patterns & Testing
Write a test in the test class // Instead of ‘Tests go here’ we write: // Creation invoice object inv1 Invoice inv1; inv1 = new Invoice("Jef","Peters", "BE-123-456-789", new Date()); inv1.addInvoiceLine("Red Paint",50.0,3); inv1.addInvoiceLine("Blew Paint",45.0,2); inv1.addInvoiceLine("Brush Medium",79.95,5); // Creation invoice object inv2: LIKE ABOVE // test inv1: compareAndReport("inv1",inv1.getTotPrice()+"", "639.75" ); // test inv2: compareAndReport("inv2",inv2.getTotPrice()+"", "586.0" ); Inherited from test.Test More OOD issues: Patterns & Testing
Just enough to compile: Invoice.java // Contains just enough code for a successful compile // All tests fail ofcourse: package invoiceApp; import java.util.ArrayList; import java.util.Date; public class Invoice{ public Invoice (String lastName, String firstName, String TAX, Date date){ } public void addInvoiceLine(String desc, double price, int qty){ } public double getTotPrice(){ return 0.0; } } More OOD issues: Patterns & Testing
Compilation C:\javaoef>javac invoiceAppTest\InvoiceAppTest.java The other classes are also compiled because they are referred to in the code. More OOD issues: Patterns & Testing
Running the test C:\javaoef>java invoiceAppTest.InvoiceAppTest ERROR! fac1 | calculated=0.0, expected=639.75 ERROR! fac2 | calculated=0.0, expected=586 Total error count (errors/tests): 2/2 More OOD issues: Patterns & Testing
Make it pass the test: Invoice.java package invoiceApp; import java.util.ArrayList; import java.util.Date; public class Invoice{ public Invoice (String lastName, String firstName, String TAX, Date date){ } private ArrayList lines = new ArrayList(); public void addInvoiceLine(String desc, double price, int qty){ InvoiceLine line = new InvoiceLine(desc,price,qty); lines.add(line); } public double getTotPrice(){ double totPrice = 0.0; for (int i=0; i < lines.size(); i++){ InvoiceLine line; line = (InvoiceLine) lines.get(i); totPrice += line.getInvoiceLinePrice(); } return totPrice; } } More OOD issues: Patterns & Testing
Make it pass the test: InvoiceLine.java package invoiceApp; public class InvoiceLine{ public InvoiceLine(String desc,double price, int qty){ this.price = price; this.qty = qty; } private double price; private int qty; public double getInvoiceLinePrice(){ return price * qty; } } More OOD issues: Patterns & Testing
Compilation and test-run C:\javaoef>javac invoiceAppTest\InvoiceAppTest.java C:\javaoef>java invoiceAppTest.InvoiceAppTest Everything works fine (2 tests passed) More OOD issues: Patterns & Testing