300 likes | 324 Views
Learn how to implement Null Object pattern, replace data values with objects, handle magic numbers & more in software refactoring. Explore practical techniques for code improvement.
E N D
Today’s Agenda • More refactoring patterns Software Testing and Maintenance 1
Introduce Null Object (1) • class Site … • Customer getCustomer () { • return _customer; • } • class Customer … • public String getName () { … } • public BillingPlan getPlan () { … } • public PaymentHistory getHistory () { … } • Customer customer = site.getCustomer (); • BillingPlan plan; • if (customer == null) plan = BillingPlan.basic (); • else plan = customer.getPlan (); • … • String customerName; • if (customer == null) customerName = “occupant”; • else customerName = customer.getName (); • … Software Testing and Maintenance 2
Introduce Null Object (2) • class NullCustomer extends Customer { • public boolean isNull () { • return true; • } • public String getName () { return “occupant”; } • public BillingPlan getPlan () { return BillingPlan.basic (); } • class Customer … • static Customer newNull () { • return new NullCustomer (); • } • class Site … • Customer getCustomer () { • return (_customer == null) ? Customer.newNull () : _customer; • } Software Testing and Maintenance 3
Introduce Null Object (3) • Customer customer = site.getCustomer (); • BillingPlan plan; • plan = customer.getPlan (); • … • String customerName; • customerName = customer.getName (); • … Software Testing and Maintenance 4
Replace Data Value with Object (1) • class Order • public Order (String customer) { • _customer = customer; • } • public String getCustomer () { • return _customer; • } • public void setCustomer (String customer) { • _customer = customer; • } • private String _customer; What if we need to add address or credit rating into a customer? Software Testing and Maintenance 5
Replace Data Value with Object (2) • class Customer { • public Customer (String name) { • _name = name; • } • public String getName () { • return _name; • } • private final String _name; • } • class Order … • public order (String customer) { • _customer = new Customer (customer); • } • public String getCustomer () { • return _customer.getName (); • } • private Customer _customer; • public void setCustomer (String customer) { • _customer = new Customer (customer); • } Software Testing and Maintenance 6
Change Value to Reference • class Order { • public order (String customer) { • _customer = Customer.create (customer); • } • } • class Customer { • private Customer (String name) { • _name = name; • } • static void loadCustomer () { • new Customer (“Bilston Gasworks”).store(); • new Customer (“Jeff Bridge”).store(); • … • } • private void store () { • _instances.put(this.getName(), this); • } • public static Customer create (String name) { • return (Customer) _instances.get(name); • } • private static Dictionary _instances = new Hashtable (); • } Software Testing and Maintenance 7
Replace Magic Number with Sym. Constant • double potentialEnergy (double mass, double height) { • return mass * 9.81 * height; • } double potentialEnergy (double mass, double height) { return mass * GRAVITATIONAL_CONSTANT * height; } Static final double GRAVITATIONAL_CONSTANT = 9.81; Software Testing and Maintenance 8
Separate Query from Modifier • int getTotalOutstandingAndSetReadyForSummaries () { • readyForSummaries = true; • return outstanding; • } intgetTotalOutstanding () { return outstanding; } voidsetReadyForSummaries () { readyForSummaries = true; } Software Testing and Maintenance 9
Parameterize Method • class Employee { • void tenPercentRaise () { • salary *= 1.1; • } • void fivePercentRaise () { • salary *= 1.05; • } • } class Employee { void raise (double factor) { salary *= (1 + factor); } } Software Testing and Maintenance 10
Replace Parameter with Explicit Methods • void setValue (String name, int value) { • if (name.equals(“height”)) { • _height = value; return; • } • if (name.equals(“width”)) { • _width = value; return; • } • } void setHeight (int arg) { _height = arg; } Void setWidth (int arg) { _width = arg; } Software Testing and Maintenance 11
Replace Parameter with Method (1) • public double getPrice () { • int basePrice = _quantity * _itemPrice; • int discountLevel; • if (_quantity > 100) discountLevel = 2; • else discountLevel = 1; • double finalPrice = discountedPrice (basePrice, discountLevel); • return finalPrice; • } • private double discountedPrice (int basePrice, int discountLevel) { • if (discountLevel == 2) return basePrice * 0.1; • else return basePrice * 0.05; • } Software Testing and Maintenance 12
Replace Parameter with Method (2) • public double getPrice () { • if (getDiscountLevel() == 2) return getBasePrice() * 0.1; • else return getBasePrice() * 0.05; • } • private double getBasePrice () { • return _quantity * _itemPrice; • } • private int getDiscountLevel () { • if(_quantity > 100) return 2; • else return 1; • } Software Testing and Maintenance 13
Replace Constructor with Factory Method (1) class Employee { static Employee create (int type) { switch (type) { case ENGINEER: return new Engineer (); case SALESMAN: return new Salesman (); case MANAGER: return new Manager (); default: // throw an exception } } • class Employee { • private int _type; • static final int ENGINEER = 0; • static final int SALESMAN = 1; • static final int MANAGER = 2; • Employee (int type) { • _type = type; • } • } Software Testing and Maintenance 14
Replace Constructor with Factory Method (2) • static Employee create (String name) { • try { • return (Employee) Class.forName (name).newInstance(); • } catch (Exception ex) { • throw new IllegalArgumentException(“Unable to instantiate ” + name); • } • } • Employee.create(“Engineer”); • Employee.create(“Manager”); • … Software Testing and Maintenance 15
Encapsulate Downcast • Object lastReading () { • return readings.lastElement (); • } • Reding lastReading = (Reading) site.lastReading (); Reading lastReading () { return (Reading) readings.lastElement (); } Reding lastReading = site.lastElement(); Software Testing and Maintenance 16
Replace Error Code with Exception (1) • class Account … • int withdraw (int amount) { • if (amount > _balance) • return -1; • else { • _balance -= amount; • return 0; • } • } • private int _balance; Software Testing and Maintenance 17
Replace Error Code with Exception (2) • class Account … • void withdraw (int amount) { • if (amount > _balance) • throw new IllegalArgumentException (“Amount too large”); • _balance -= amount; • } • private int _balance; Software Testing and Maintenance 18
Replace Error Code with Exception (3) • class Account … • void withdraw (int amount) throws BalanceException { • if (amount > _balance) • throw new BalanceException (); • _balance -= amount; • } • private int _balance; Software Testing and Maintenance 19
Pull Up Constructor Body • class Manager extends Employee … • public Manager (String name, String id, int grade) { • _name = name; • _id = id; • _grade = grade; • } class Employee … public Employee (String name, string id) { _name = name; _id = id; } class Manager extends Employee … public Manager (String name, String id, int grade) { super (name, id); _grade = grade; } Software Testing and Maintenance 20
Extract Subclass (1) • class JobItem … • public JobItem (int unitPrice, int quantity, boolean isLabor, Employee employee) { • _unitPrice = unitPrice; • _quantity = quantity; • … • } • public int getTotalPrice () { • return getUnitPrice () * quantity; • } • public int getUnitPrice () { • return (_isLabor) ? _employee.getRate() : _unitPrice; • } • …. • class Employee… • public Employee (int rate) { • _rate = rate; • } • public int getRate () { • return _rate; • } • private _rate; Software Testing and Maintenance 21
Extract Subclass (2) • class JobItem … • public JobItem (int unitPrice, int quantity, boolean isLabor) { • _unitPrice = unitPrice; • _quantity = quantity; • _isLabor = isLabor; • } • public int getUnitPrice () { • return _unitPrice; • } • …. • class LaborItem extends JobItem … • public LaborItem (int quantity, Employee employee) { • super (0, quantity, true); • _employee = employee; • } • public int getUnitPrice () { • return _employee.getRate (); • } Software Testing and Maintenance 22
Extract Subclass (3) • Modify calls to the constructor of the job item where a labor item is constructed JobItemj = new JobItem (0, 5, true, kent); JobItemj = new LaborItem (5, kent); Software Testing and Maintenance 23
Form Template Method (1) • public String statement () { • Enumeration rentals = _rentals.elements (); • String result = “Rental Record for ” + getName () + “\n”; • while (rentals.hasMoreElements ()) { • Rental each = (Rental) rentals.nextElement (); • // show figures for this rental • result += “\t” + each.getMovie.getTitle() + “\t” • + String.valueOf(each.getCharge()) + “\n”; • } • // add footer lines • result += “Amount owed is“ + String.valueOf(getTotalCharge()) • + “\n”; • result += “You earned “ • + String.valueOf(getTotalFrequentRenterPoints()) • + “ frequent renter points”; • return result; • } Software Testing and Maintenance 24
Form Template Method (2) • public String htmlStatement () { • Enumeration rentals = _rentals.elements (); • String result = “<H1>Rental Record for <EM>” + getName () + “</EM></H1><P>\n”; • while (rentals.hasMoreElements ()) { • Rental each = (Rental) rentals.nextElement (); • // show figures for this rental • result += each.getMovie.getTitle() + “: ” • + String.valueOf(each.getCharge()) + “<BR>\n”; • } • // add footer lines • result += “<P>You owe <EM> “ + String.valueOf(getTotalCharge()) • + “</EM><P>\n”; • result += “On this rental you earned “ • + String.valueOf(getTotalFrequentRenterPoints()) • + “ </EM>frequent renter points <P>”; • return result; • } Software Testing and Maintenance 25
Form Template Method (3) Customer Statement Text Statement HTML Statement Software Testing and Maintenance 26
Form Template Method (4) • class Statement … • public String value (Customer customer) { • Enumeration rentals = customer.getRentals (); • String result = headerString(customer); • while (rentals.hasMoreElements ()) { • Rental each = (Rental) rentals.nextElement (); • // show figures for this rental • result += eachRentalString(each); • } • // add footer lines • result += footerString(customer); • return result; • } • abstract String headerString (Customer customer); • abstract String eachRentalString (Rental rental); • abstract String footerString (Customer customer); Software Testing and Maintenance 27
Form Template Method (5) • class TextStatement … • String headerString (Customer customer) { • return “Rental Record for “ + customer.getName () + “\n”; • } • String eachRentalString (Rental rental) { • return “\t” + rental.getMovie().getTitle() + “\t” • + String.valueOf(rental.getCharge() + “\n”; • } • String footerString (Customer customer) { • return “Amount owed is “ • + String.valueOf(customer.getTotalCharge()) + “\n” • + “You earned “ • + String.valueOf(customer.getTotalFrequentRenterPoints()) • + “ frequent renter points”; • } • // similar for class HtmlStatement Software Testing and Maintenance 28
Replace Inheritance with Delegation (1) • class MyStack extends Vector { • public void push (Object element) { • insertElementAt (element, 0); • } • public Object pop () { • Object result = firstElement (); • removeElementAt (0); • return result; • } • } Software Testing and Maintenance 29
Replace Inheritance with Delegation (2) • class MyStack { • private Vector _vector = new Vector (); • public void push (Object element) { • _vector.insertElementAt (element, 0); • } • public Object pop () { • Object result = _vector.firstElement (); • _vector.removeElementAt (0); • return result; • } • public int size () { • return _vector.size (); • } • public boolean isEmpty () { • return _vector.isEmpty (); • } • } Software Testing and Maintenance 30