Contents [0/22] |
Overview of Today's Class [1/22] |
Homework: Discussion [2/22] |
UML: Interaction Diagrams [3/22] |
UML: Sequence Diagrams [4/22] |
UML: State Diagrams [5/22] |
Patterns: Intro to Patterns [6/22] |
Patterns: Classification and Organization [7/22] |
Patterns: GoF principles [8/22] |
Strategy: Definition [9/22] |
Strategy: Example [10/22] |
Strategy: Code [11/22] |
Patterns: Another Strategy Example [12/22] |
Java: Identifiers [13/22] |
Java: coercion [14/22] |
Java: Data [15/22] |
Java: Reference Types [16/22] |
Java: Call by ? [17/22] |
Java: Classes [18/22] |
Java: Class Declaration [19/22] |
Java: Object Creation [20/22] |
Java: Types of Storage [21/22] |
Homework: Assignment #3 [22/22] |
Overview of Today's Class [1/22] |
Homework Discussion
UML object diagrams (sequence, collaboration, state)
Intro to patterns, The Strategy Pattern
More Java/00
Homework: Discussion [2/22] |
Sample solution
UML: Interaction Diagrams [3/22] |
Describes how a group of objects work together. Shows the objects and the messages passed between them. Models dynamic behavior.
Comes in two flavors:
These are very good at showing the collaborations between objects.
UML: Sequence Diagrams [4/22] |
Shows:
Example: p 37
UML: State Diagrams [5/22] |
State
Initial States
Final States
Transitions - moving from state to state based on events
event [guard]/actions
Example: p 39,40
The State design pattern represents this behavior
Patterns: Intro to Patterns [6/22] |
What is a pattern?
"Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice"
History: Architecture background - Christopher Alexander discovered and cataloged patterns in architecture.
Purpose:
Goals
Patterns:
Used in:
The GoF book documents 23 of these patterns.
To define a pattern, need the following:
In practice, we will use the following template
Patterns: Classification and Organization [7/22] |
Patterns are divided up several ways:
Class vs. Object
Creational vs. Structural vs. Behavioral
Purpose | ||||
Creational | Structural | Behavioral | ||
Scope | Class | Factory Method (107) | Adapter (class) (139) | Interpreter (243) Template Method (325) |
Object | Abstract Factory (87) Builder (97) Prototype (117) Singleton (127) |
Adapter (object) (139) Bridge (151) Composite (163) Decorator (175) Facade (185) Flyweight (195) Proxy (207) |
Chain of Responsibility (223) Command (233) Iterator (257) Mediator (273) Memento (283) Observer (293) State (305) Strategy (315) Visitor (331) |
Patterns: GoF principles [8/22] |
In the GoF patterns book, we see a few principles repeated again and again. These principles shape the pattern design and intent in most of the patterns we will study. They are:
The last one is the opposite of focusing on the cause of redesign. Instead of focusing on what might force a change to a design, consider what you want to be able to change without redesign. The focus is on encapsulating the concept that varies, a theme of many design patterns [GoF p29] |
Strategy: Definition [9/22] |
switch
or if -
then -else
statements in your code to define
different behaviors in your classComparator
objects
Strategy: Example [10/22] |
From chapter 14 of Design Patterns Explained, we have an example for a Tax calculation. The classes are as follows:
Context = SalesOrder
CalcTax = Strategy
USTax, CanTax = ConcreteStrategy
Others: Configuration, TaskController
Strategy: Code [11/22] |
SalesOrder, the Context
package example.strategy; public class SalesOrder { // makes a bogus sales order and returns the tax public double calcTax() { String item1 = "book"; String item2 = "gum"; double item1qty = 2; double item2qty = 4; double item1price = 14.32; double item2price = 0.34; double totalTax = 0.0; CalcTax taxer = Configuration.getTaxer(); totalTax += taxer.taxAmount(item1, item1qty, item1price); totalTax += taxer.taxAmount(item2, item2qty, item2price); return totalTax; } }
CalcTax, the Strategy
package example.strategy; public interface CalcTax { public double taxAmount(String item, double qty, double price); }
USTax, CanTax = ConcreteStrategies
package example.strategy; public class USTax implements CalcTax { public double taxAmount(String item, double qty, double price) { // crude algorithm if("book".equals(item)) { return qty * price * 0.04; } else { return qty * price * 0.05; } } } package example.strategy; public class CanTax implements CalcTax { public double taxAmount(String item, double qty, double price) { // crude algorithm, Canada much more expensive than US! if("book".equals(item)) { return qty * price * 0.4; } else { return qty * price * 0.5; } } }
Others: Configuration
package example.strategy; public class Configuration { // default to US private static CalcTax taxer = new USTax(); public static CalcTax getTaxer() { return taxer; } public static void setTaxer(String name) { if("can".equals(name)) { taxer = new CanTax(); } else { taxer = new USTax(); } } }
TaskController: the driver
package example.strategy; package example.strategy; public class TaskController { public static void main(String args[]) { SalesOrder order = new SalesOrder(); Configuration.setTaxer("us"); System.out.println("The tax for the U.S. is " + order.calcTax()); Configuration.setTaxer("can"); System.out.println("The tax for Canada is " + order.calcTax()); } }
Patterns: Another Strategy Example [12/22] |
From the book, page 297-298
The Strategy: Function
interface Function { double apply(double x); }
The Concrete Strategies: Sine, Cosine
public class Cosine implements Function { public double apply(double x) { return Math.cos(x); } } public class Sine implements Function { public double apply(double x) { return Math.sin(x); } }
The Context: MultiPlotter
import java.awt.*; public abstract class MultiPlotter extends Plotter { abstract public void initMultiPlotter(); public void init() { super.init(); initMultiPlotter(); } final public void addFunction(Function f, Color c) { if (numOfFunctions < MAX_FUNCTIONS && f != null) { functions[numOfFunctions] = f; colors[numOfFunctions++] = c; } } protected void plotFunction(Graphics g) { for (int i = 0; i < numOfFunctions; i++) { if (functions[i] != null) { Color c = colors[i]; if (c != null) g.setColor(c); else g.setColor(Color.black); for (int px = 0; px < d.width; px++) { try { double x = (double) (px - xorigin) / (double) xratio; double y = functions[i].apply(x); int py = yorigin - (int) (y * yratio); g.fillOval(px - 1, py - 1, 3, 3); } catch (Exception e) {} } } } } public double func(double x) { return 0.0; } protected static int MAX_FUNCTIONS = 5; protected int numOfFunctions = 0; protected Function functions[] = new Function[MAX_FUNCTIONS]; protected Color colors[] = new Color[MAX_FUNCTIONS]; }
And the implementation of the MultiPlotter
import java.awt.Color; public class PlotSineCosine extends MultiPlotter { public void initMultiPlotter() { addFunction(new Sine(), Color.green); addFunction(new Cosine(), Color.blue); } }
Java: Identifiers [13/22] |
One of the major advantages of assembly language over machine language is the ability to refer to data memory using names, or identifiers.
Some important properties of identifiers:
References are sometimes referred to as boxed values.
Plain values are then called unboxed.
A declaration is a statement that, when executed
,
binds a name to a data-memory location.
The scope of a declaration is the text of the program in which the binding has effect.
Lifetime is a dynamic property. Scope is a static property.
Value/Reference is really part of the type, but it is worth discussing separately.
A variable of value type T
(synonym:
unboxed type) stores a value of type T
.
A variable of reference type T
(synonyms: pointer type, boxed, type) stores a pointer to a
value of type T
.
In java, all base-type identifiers hold values; all object-type identifiers hold references.
int x = 0; // value type (unboxed) String s = "dog"; // reference type (boxed)
primitive types are
boolean
byte, short, int, long
char
float, double
Java has wrapper classes in the java.lang
package that wrap all the primitive types.
String
in Java is not a primitive type, but a class. However
it behaves like a special class, allowing string concatination using primitive
operators.
In Java, objects are always boxed (ie, identified by reference).
In C++, objects of any class may be boxed or unboxed. For example:
string* sp = new string("dog"); // boxed (requires delete) string s = string("cat"); // unboxed (no delete needed)
Java: coercion [14/22] |
There are many types of conversions that take place in Java:
These will show up in
Widening and narrowing of references is done via casting (later).
public class Coercion { final static int X = 33; public static void main(String args[]) { int x = 5; double y = 4.5; System.out.println("x + y = " + (x + y)); // widening //int z = y; (narrowing - not allowed) int z = (int)y; // lossy short xx = X; // not lossy, java will do this for you // short xy = z; // lossy - not allowed } }
Java: Data [15/22] |
Data is stored in memory at runtime.
Some important properties of data:
The type of data indicates the meaning of the bits in memory. The lifetime of data begins when memory is allocated; the lifetime ends when memory is de-allocated. Data that may change is called mutable. Data that may not change is called immutable (some synonyms are constant and final). |
Java: Reference Types [16/22] |
References in Java are 32-bit pointers. They hold indirect references to Object or Array instances
Java treats an Array of any type as an Object
Reference types (objects) are created on the heap. Unlike C++, there are no ways to manipulate this reference to point to different places in memory, or perform pointer arithmetic on it.
Items created on the heap are garbage collected. Since Java 1.2, you have been able to have some control over when things are GC'd using the Reference Object API. But even with some control over GC, Java far from a Real Time environment.
Primitive types are created on the stack
Java: Call by ? [17/22] |
What happens here?
public class C1 { public void inc(int i) { i++; } } C1 c1 = new C1(); int k = 1; c1.inc(k); System.out.println(k);
vs.
public class C2 { public void inc(Point p) {p.x++; p.y++; } } C2 c2 = new C2(); Point p = new Point(10.0,10.0); c2.inc(p); System.out.println(p);
So what is going on?
Call by reference vs Call by value vs "Call by sharing" (from Kim Bruce)
Java: Classes [18/22] |
What is a class?
What is the relation between classes and objects?
Which of an object's properties are fixed by its class?
An object is an instance of a class. The class fixes: the name and type of fields and methods, and the value of methods. Fields are data, methods are code used to manipulate the data. The only thing that varies for each instance are the field values. |
Java: Class Declaration [19/22] |
For classes:
[ClassModifiers] class ClassName [extends SuperClass]
[implements Interface1, Interface2, ...] {
ClassMember Declarations
}
Modifiers can be
public
- only one of these per file!abstract
final
For methods:
[MethodModifiers] ReturnType MethodName([ParameterList]) {
Statements
}
Modifiers can be
public
protected
private
static
final
abstract
synchronized
native
For fields only
volatile
transient
Note that final
has completely different meanings
in different contexts. Remember, a final
parameter is
not like const
in C++
Java: Object Creation [20/22] |
How are objects specified and created?
Prototype-based languages allow the static description of objects (as literal values). To create new objects at runtime, they use cloning. JavaScript is an example of a prototype-based language. It doesn't distinguish between classes and instances. Any object can be used to create a new object by cloning it.
In JavaScript, an object can go from String to Integer to String without being re-instantiated.
Class-based language allow the static description of classes. To create objects at runtime, use a constructor.
When a reference type is created, only a storage location for the reference is made, not the objects themselves.
Point p; // reference variable of type Point p = new Point(); // new Instance of point int[] ia; // reference variable of array of integers ia = new int[3]; // an array of size 3 Point[] pArray; // reference variable of array of Points pArray = new Point[3]; // an array of Points. They are all null! // can use an array initializer ia = {1,2,3}; pArray = { new Point(), new Point() } ;
Java: Types of Storage [21/22] |
What are class fields, object fields and method variables?
In java, a class field is also called static
field.
Object fields are also called instance fields.
When one discusses a field
, one is usually referring
to an instance field.
Class fields are stored once for the class. Lifetime is life of the class in memory. All instances (if any) share the same data.
Class fields are stored statically. For our purposes they are immortal.
Instance fields are stored once for the object. Lifetime is life of the object. All instances have separate data.
Instance fields are stored in an object record on the
heap. Heap allocation is indicated by the use of
new
, which returns a reference to the heap.
Java objects are garbage collected: an object dies
when the last reference to that object dies. (The memory
is reclaimed when the garbage collection thread removes the
object that the reference referred to).
Class fields and methods are referred to in java by ClassName.classMethod(Parameters) or ClassName.classField, or by an object reference: objectReference.classMethod(Parameters) or objectReference.classField. Instance fields and methods have to be referred to by objectReference.instanceMethod(Parameters) or objectReference.instanceField. You should use the ClassName, not an objectRefrence to access class fields and methods.
Class fields can be initialized with default values, in an initializer in its declaration, or in a static initialization block (like a class initialization block, but it is run once for all classes). Do not use the constructor.
Method variables (local variables and parameters) are stored once for each method invocation. Lifetime is life of the method invocation.
Method variables are stored in an activation record (or frame) on the stack.
In practice, the stack runs out of space when the OS runs out
of space. The heap runs out of space when the heap size is
reached. You can control this with -Xms
and
-Xmx
options on the java command line.
Homework: Assignment #3 [22/22] |
Read Jia chapter 6.
And read this tutorial of junit.
Goal - to implement the Strategy pattern.
Update your homework #2 solution (using any parts that you would like)
to use the Strategy pattern. Put it in the
package se450.studentid.hw3
where
studentid
is your DePaul ID.
Assume that you have a file of flight records, like last week. It is a text file in which each line contains a single record, and each record consists of the following colon-delimited fields:
Airline Code: Airplane Type: Flight Number : Departing Airport : Arriving Airport: Time: # of passengers
A sample line is as follows:
ASA:B73Q:144:ORD:SFA:13:230
Assume that the time is just a whole hour in 24HH format, as an integer. The passenger count is also an integer. All other records are strings
You are going to implement three different pricing models for an airline, and calculate the revenue generated by each strategy (model) for the total of the airline's flights in the file.
The Strategy pattern is a good example of Subtyping. In other words,
we are programming to an interface, not Subclassing, in which case we would
be using an abstract class. So create a generic Strategy interace that is
part of the hw3 package, in my case it would be se450.mwright1.hw3.Model.
It will have one method, long getRevenue(List flights)
which takes a List
of flights as its only parameter and
returns a long of whole dollars.
Then create 3 different concrete strategies, SinglePrice
,
TwoClasses
, and MultiClass
. These will all implement the
Model interface. The Model interface should define a constant for the
base ticket price ($300), and the fixed cost to fly a plane ($50,000).
For now, we'll ignore distance and different plane sizes.
The three models will behave as follows:
Treat the Main program as the Context. In other words, it will have to switch between the ConcreteStrategies as needed.
Use the Airline and Flight classes from last week. The Main
class's main()
method should
take two command line arguments, the filename and the airline code to be
processed and return results for all parts of the program. The program
should return the total revenue for the day's flights for the airline
code passed in. Proper error handling is expected for conditions like
no file found, no flights for an airline, etc. Include a good usage statement
if the program is invoked with no arguments.
Grading is as follows:
Continue to ask questions on the discussion list
Submit
a zip
file that contains all your source code and
grader.txt
. As always, make sure that your
source is in the correct package for your code. The
grader will take off points if you have extra or incorrect
directories included.
To test your homework, take the zip file, move it to a new directory, unzip it, and then run
javac -classpath . se450\studentid\hw3\Main.java java -classpath . se450.studentid.hw3.Main
On Unix, you will need to change your \ to /. If this doesn't work, your homework submission isn't correct! (and you will miss the correct submission points on your homework)
You can use the grader.txt
file from the previous homework.
Due next Monday(1/27) at 5:30 PM
Revised: 1/19/2003