Classes, interfaces, & documentation Review of basic building blocks
Objects Data structures literally, storage containers for data constitute object knowledge or state Operations an object can perform on data are its actions Object knowledge and actions are specified by its class In a class definition: knowledge: instance variables actions: instance methods
Information hiding Separation of program specification from its implementation several programmers can work on different facets of same problem, knowing specs others will meet (and not having to know how specs are met) an ADT (abstract data type) is a class presented to client programmers with information hiding What do you, as the client programmer, need to know?
Class Basis for a Java program, but more to the point: specification for a data type An object is an instance of a class Class specification includes these members: data (variables) constructor(s) methods
Interfaces What is an interface? Google says: For example user interface
Again, from Google: Interfaces Which sounds suspiciously like what we just called a class specification because it is! From the Java Tutorial: objects define their interaction with the outside world through the methods they expose. Methods form the object s interface with the outside world.
Information hiding, again Classic OOP theory suggests that we should define an object s interface before we design its implementation; lots of good reasons for this: Makes it easy to break up a large programming task so a team can handle it Everybody has a clear idea of what to expect from others methods even though they haven t been written yet Test code can be written before implementation: should be able to use the same test code regardless of implementation
Interfaces & information hiding A class s interface consists of its public portions: typically methods, occasionally data (constants only, except in very rare cases) Separating implementation from specification means that implementation can change (and improve) without interfering with code that depends on the original class to have the same interface
In Java, we take it a step further
Example public interface Container { public void insert (Object data); public Object retrieve (Object target); public boolean remove (Object target); public boolean contains (Object target); public int getsize(); public int getcapacity(); } The public methods are specified: we know how to call them (and can make guesses about what they do) We know nothing about the data structures and algorithms that define the implementation of the class One important point: an interface is not a class We can t create objects using this interface type directly We need a class that implements the interface
Example continued public class SadSack implements Container { public void insert (Object data) {} public Object retrieve (Object target) {return null;} public boolean remove (Object target) {return false;} public boolean contains (Object target) {return false;} public int getsize() {return 0;} public int getcapacity() {return 0;} } This class could be used to write a quick test driver More sophisticated implementations could use the same test code
Test code (separate handout) Good testing practice requires that we: think ahead about how our program should behave under a variety of conditions run tests to verify the correctness of the program under each of these conditions Setting up a sample data set to test against is important: a simple list of values to try may be appropriate for some programs a ready-made data file would be more appropriate for others.
Documentation: we can do better! Goals: Make your code readable to other programmers Be able to make sense of your own code, much less others, a year from now Self-documenting code: naming things deliberately so that their reason for being becomes obvious Be consistent with: indentation use of white space bracket style anything else you can think of!
Clarity Client programmers need to be able to comprehend your class s interface: confused programmers write buggy code Clarity often comes down to documentation: explain what a method does in terms you (and your clients) can easily understand 14
Programming by Contract Spell out responsibilities: of caller of implementor Increase reliability Increase efficiency 15
Pre and post conditions Represent a contract of sorts between the provider of a service (e.g. a Java class) and the client who uses that service (another programmer) Pre and post condition statements are the documentation you can and should write before you write any code they are, or at any rate should be, part of the interface
Preconditions State what must be true about the data being passed to a method For example, if I m writing a method to calculate the square root of a number, I can only operate on positive values so I state this as a precondition The contract: if you meet my precondition, my method will work as advertised; if not, anything could happen (I cannot be held responsible for your bad data choices!)
Preconditions When precondition fails, service provider may throw exception return false answer corrupt data So the client is entirely responsible for meeting the precondition; but the careful service provider will: Inform the client of the precondition (documentation!) Check the validity of the precondition before proceeding with the method (option 1, above, is usually the best option!) 18
Preconditions: some caveats Excessive error checking is costly so service code should throw exceptions, not try to catch them (leave that up to clients) Returning dummy values can complicate testing worked okay for our very generic toy example, but in most cases it s not the best option we want our programs to produce reliable, and reliably correct, results 19
Exceptions in the contract Exception throw also part of the contract Caller can rely on behavior Exception throw not always result of precondition violation Method on next slide has no precondition (because it takes no arguments) but can throw exception anyway, and client should know under what conditions 20
Example We want to remove first element from a container Since it s always the first element, we don t need an argument so what happens if the container is empty? /** @throws IllegalArgumentException if queue is empty */ public Message removefirst() { if (count == 0) throw new IllegalArgumentException(); Message r = elements[head]; } 21
Postcondition Condition that the service provider guarantees Describes what the method does (not the algorithm, just the results) If the method returns a value, describes that value Otherwise, just describes what happens when method is called 22
Example Is this sufficient documentation? How can it be improved?
Example What is the precondition? Where/how should it be stated? What is the postcondition?
Javadoc The previous examples contained a commenting style that may not be familiar to some of you: javadoc A javadoc comment is a multiline comment that begins with /** and ends with */ The first line of a javadoc comment should be a concise description of the class or method it refers to Various embedded tags can be used to create standardized comments (like what you see in the Java API)
Javadoc tags @author: Take credit for your work! @version: could be a number or a date; one way to keep track of revisions @param: describe one method parameter per tag can be used to describe pertinent preconditon @return: describe return value can be used to describe postcondition @throws: use for exceptions code might spawn; can be another place to describe precondition
Back to classes We have seen that we can specify what a class does independent of how its methods actually work But sooner or later, we need to think in terms of the data representation and the algorithms that operate on that data The next several slides will take us through that process
Example: a throttle Models physical object that controls flow of fuel to an engine Attributes include: shutoff point: 0% fuel flow progressively higher flow rates represented by lever position; maximum is fully open, 100% fuel flow each position between 0 and max is proportionately higher than the previous source: www.flypfc.com
Member variables We need to represent the attributes described on the previous slide: number of throttle positions (max) current position (position) Fill in the blanks of the class definition (next slide)
public Throttle { // member variables: private max; position;
Constructor Method for initializing instance variables of a new object For the Throttle class, we ll define two constructors: a default constructor that presets a chosen maximum value a constructor that allows the client programmer to choose the maximum value
// class definition continued // default constructor: public Throttle () { max = 100; position = 0; } // second constructor: public (int cap) { }
Questions What happens if you don t define a constructor for your class? Is there an advantage to defining your own constructor?
Instance methods - Accessors Accessors provide information about an object s state Accessors do not change the state of the object An accessor method always returns a value
Why not use public instance variables instead? Accessors support the principle of information hiding; client programmers don t need to know anything about implementation (e.g., names of the variables), just how to get the information they need (return value from accessor) Use of accessors (instead of public variables) allows change to the implementation of a class without any required change to client code Private data can t be modified in ways the author of the class didn t intend
Accessors for the Throttle class getflow: returns value indicating proportion of max is currently flowing ison: returns value indicating whether or not throttle is turned on
// accessor methods public getflow () { } public ison () { }
Instance methods - modifiers Also known as mutators: methods that make specific changes to object s state Usually void why?
Modifiers for Throttle class shutoff: turns off Throttle shift: moves Throttle s position up or down by a specific amount how will this amount be specified? how do we handle a value that goes out of bounds (<0 or >max)?
// modifier methods: public void shutoff () { } public void shift ( setting) { }
Documentation for Data Pre and post conditions are statements about class methods Invariants are statements about instance variables
Class Invariants Condition that is true after every constructor (no invalid objects can be created) preserved by every method (if it's true before the call, it's again true afterwards) Useful for checking validity of operations 42
Class invariants As long as instance fields are private, you have complete control over object modification Can guarantee certain values are within legal range, certain references are not null Invariant is appropriate tool for documenting such a guarantee 43
Using a class Once a class has been established, you can use instances of the class (objects) in other programs Remember, the class is a data type; in order to perform the actions specified by its instance methods, we need to instantiate an object
Instantiating objects Object creation is a two step process: declaration: Throttle choke; initialization: choke = new Throttle(50); This is often done in a single step: Throttle choke = new Throttle(50);
Calling methods Once we have an object, we can call instance methods defined in the class The calling object and method are specified, along with any necessary arguments; syntax: objectname.methodname(arg(s)) Write a line of code that adjusts choke (the Throttle object created on the previous slide) up 3 steps:
Key points to remember Objects are instances of classes Object names are references to objects Objects are created using the new operator and one of the class s constructors What happens in the following situation? How do we avoid the problem? Throttle uhoh; uhoh.shutoff();
Null references Instead of creating an object immediately, you can declare a variable and set it to null: Throttle t = null; You can also set an object reference to null after it s been in use: Throttle t = new Throttle(); t.shift(30);. // after a while, finished with this object t = null;
Why use null references? Helps conserve system resources; even though Java has automatic garbage collection, not a bad idea to help out Means every object reference can be counted on to be in one of two conditions: refers to an object (not null) refers to NO object (null) We can test an object reference to see if it is null; this means we can always avoid a NullPointerException; see code on next slide
// One way: if (t!= null) System.out.println( Current setting is + t.getflow()); else System.out.println( Can t get setting no active throttle ); // Another way: try { System.out.println( Current setting is + t.getflow()); } catch (NullPointerException e) { System.out.println( Can t get setting no active throttle ); }
Reference variables & assignment Consider the code snippet below: Throttle t1=null, t2=null; t1 = new Throttle(100); t2 = t1; t2.shift(50); System.out.println( Current value of t1 is + t1.getflow()); What is output? Why?
Sketch of situation Since both variables refer to the same object, a change invoked by one shows up in both
A better way Using the assignment operator with objects does not copy the object, it only copies its address, leading to the situation we ve just seen If we need two identical objects, we could simply instantiate two objects with the same parameters: Throttle t1 = new Throttle(100); Throttle t2 = new Throttle(100); What would this look like? Is (t1 == t2) a true statement?
A better way To ensure that two object references aren t pointing to the same object, the best option is to define a clone method for the data type you re creating All classes have an inherited clone method (from Object), but it doesn t really help matters, as we will see If you are defining a new clone method, you should tag your class as implementing the Cloneable interface this signals to other programmers that you have a valid clone method