CSC223 2004F, Class 40: Notes on Midterm Admin: * Missing today: Omondi, Ryan, Louisa * Midterm returned and discussed * Final distributed. Due Friday of final's week. * Read chapter 5 of Design Patterns for Wednesday. * Clean up your stuff before you leave Overview: * General notes * JCF * Factories * Introspective Testing * Refactoring * Q and Q On the "cover sheet" * 1: check or nothing (everyone got full points) * 2: -5 * 3: -10 * 4: +1 * name: 2 * times: 3 * errors: 5 * jello: 1 Midterm grade: 2/3 * higher + 1/3 * lower It was longer than I'd planned! * Mostly due to problems with introspection Sam's takehome exams are intended to be learning processes * But also an opportunity to apply the knowledge you've learned Introspection, revisited * Key ideas in introspection: * You can treat classes as objects * You can treat constructors and methods as objects * How? * java.lang.Class - The class for classes * java.lang.introspect.Method - The class for methods * java.lang.introspect.Constructor - The class for constructors Problem 4: Factories package rebelsky.takehome01; /** * Things that know how to build objects by parsing strings. * * @author Samuel A. Rebelsky * @version 1.0 of November 2004 */ public interface ParsingFactory { /** * Convert a string to an object of the appropriate type. */ public Object parse(String s) throws Exception; } // interface ParsingFactory Suggestion: Rather than making IntegerParsingFactory, StringParsingFactory, BigIntegerParsingFactory, etc., we should create a general "ParsingFactoryBuilder" that, given a class name, builds a parsing factory. package rebelsky.takehome01; /** * Something that knows how to build ParsingFactory objects. * * @author Samuel A. Rebelsky * @version 1.0 of November 2004 */ public class FactoryBuilder { /** * Build a new ParsingFactory from a class. */ public static ParsingFactory makeFactory(final Class c) throws Exception { return new ParsingFactory() { public Object parse(String s) throws Exception { Class[] formals = new Class[]{ Class.forName("java.lang.String") }; Object[] actuals = new Object[]{ s }; return c.getConstructor(formals).newInstance(actuals); } // parse(String) }; } // makeFactory() /** * Build a ParsingFactory from a string that names a class. */ public static ParsingFactory makeFactory(String name) throws Exception { return makeFactory(Class.forName(name)); } // makeFactory(String) } // class FactoryBuilder Alternative strategy: Create a "helper" class: GenericParsingFactory public class GenericParsingFactory { Class c; public GenericParsingFactory(Class _c) { this.c = _c; } public Object parse(String s) throws Exception { Class[] formals = new Class[]{ Class.forName("java.lang.String") }; Object[] actuals = new Object[]{ s }; return this.c.getConstructor(formals).newInstance(actuals); } // parse(String) } public class FactoryBuilder { public ParsingFactory(Class c) { return new GenericParsingFactory(c); } --- /More Introspection/ * Could you implement JUnit if you had to? * Variation * Find all the unary integer methods in the class * Call each of them on a variety of values * Coding: * Field for all unary integer methods (of type Method[]) * Better than recomputing them each time you need them (an instance of refactoring) * Some of you had that field as type Vector - Had to cast every time you used an element as a method * If you want condition A to be true and condition B to be true, write if (A && B) { ... } * Don't write if (A) { if (B) { ... } } * Clever ideas: * Ability to turn off printing of call stack * Permit both int and Integer /Refactoring/ * Sam expected: * Look, these two methods have nearly identical code. I'll parameterize that code and shove it in a separate method. * Look, these two classes share the same method. I'll put it in a separate class and either inherit from that class or contain that class. * Sam also saw * Look, this class serves two purposes, I'll make it two classes * Look, I have incredibly repetitive methods that refer to different fields, I'll encapsulate the methods and fields in separate objects Rather than getHomeAreaCode getWorkAreaCode getCellAreaCode getHomeAreaBase getWorkAreaBase getCellAreaBase Add a PhoneNumber class which areaCode() and have getHomePhoneNumber().areaCode() getWorkPhoneNumber().areaCode) getCellPhoneNumber().areaCode() getHomePhoneNumber().base() getWorkPhoneNumber().base() getCellPhoneNumber().base()