Name implies Services (interface syntax + semantics)
James Gosling: What is the API to Windows? Nobody knows. In fact, even Microsoft doesn't know what the Windows API is. Because they publish an API, but lots of people sneak in through back doors. [...]Because there isn't a really good, strong interface notion in C, people just sort of reach in through the back doors. And they do God knows what. And so when Microsoft goes to release a new version of Windows, what they essentially have to do is test everything.
It was a very important property of interfaces that they are very strict. That wasn't just me deciding to be nasty. That was the world is madness if the contracts aren't strict. Because then all of a sudden--the whole notion of object-oriented programming falls apart. You lose the ability to unplug this and plug that in. If you don't know what the shape of the plug is, how do you know it can plug in?
get()
and set()
methods are very data
oriented
1 package com.artima.examples.matrix.ex1;
2
3 import java.io.Serializable;
4
5 /**
6 * Represents a matrix each of whose elements is an <CODE>int</CODE>.
7 *
8 * @author Bill Venners
9 */
10 public class Matrix implements Serializable, Cloneable {
11
12 private int[][] elements;
13 private int rowCount;
14 private int colCount;
15
16 /**
17 * Construct a new <EM>square zero matrix</EM> whose order is determined
18 * by the passed number of rows. (The matrix is square. It has the same
19 * number of rows and columns.) All elements of the new
20 * <CODE>Matrix</CODE> will be initialized to zero.
21 *
22 * @param rows The number of rows and columns in the new
23 * <CODE>Matrix</CODE>
24 * @exception IllegalArgumentException if <code>rows</code> is less than
25 * zero
26 */
27 public Matrix(int rows) {
28
29 if (rows < 1) {
30 throw new IllegalArgumentException();
31 }
32
33 elements = new int[rows][rows];
34 rowCount = rows;
35 colCount = rows;
36 }
37
38 /**
39 * Construct a new <EM>zero matrix</EM> whose order is determined by the
40 * passed number of rows and columns. The order is (rows by columns).
41 * All elements of the new <CODE>Matrix</CODE> will be initialized to
42 * zero.
43 *
44 * @param rows The number of rows in the new <CODE>Matrix</CODE>
45 * @param cols The number of columns in the new <CODE>Matrix</CODE>
46 * @exception IllegalArgumentException if <code>rows</code> or
47 * <code>cols</code> is less than zero
48 */
49 public Matrix(int rows, int cols) {
50
51 if (rows < 1 || cols < 1) {
52 throw new IllegalArgumentException();
53 }
54
55 elements = new int[rows][cols];
56 rowCount = rows;
57 colCount = cols;
58 }
59
60 /**
61 * Construct a new <CODE>Matrix</CODE> whose elements will be initialized
62 * with values from the passed two-dimensional array of
63 * <CODE>int</CODE>s. The order of the matrix will be determined by the
64 * sizes of the passed arrays. For example, a two dimensional array
65 * constructed with <CODE>new int[4][9]</CODE>, would yield a matrix
66 * whose order is 4 by 9. The lengths of each of the arrays held from the
67 * initial array must be the same. The two-dimensional array passed as
68 * <CODE>init</CODE> will not be used as part of the state of the newly
69 * constructed <CODE>Matrix</CODE> object.
70 *
71 * @param init A two-dimensional array of <code>int</code>s with which
72 * to initialize the new <code>Matrix</code>
73 * @exception IllegalArgumentException if the length of any passed array
74 * is zero, or if the length of all the secondary arrays are not
75 * equivalent.
76 */
77 public Matrix(int[][] init) {
78
79 checkValidity(init);
80
81 elements = (int[][]) init.clone();
82 rowCount = init.length;
83 colCount = init[0].length;
84 }
85
86 /**
87 * Returns the element value at the specified row and column.
88 *
89 * @param row The row of the element whose value is to be returned
90 * @param col The column of the element whose value is to be returned
91 * @return value of element at specified row and column
92 * @exception IndexOutOfBoundsException if <code>row</code> is less than
93 * zero or greater than the number of rows minus 1, or if
94 * <code>col</code> is less than 0 or greater than the number of
95 * columns minus 1.
96 */
97 public int get(int row, int col) {
98 checkIndices(row, col);
99 return elements[row][col];
100 }
101
102 /**
103 * Sets the element value at the specified row and column to the
104 * passed value.
105 *
106 * @param row The row of the element whose value is to be set
107 * @param col The column of the element whose value is to be set
108 * @param value The new value of the element indicated by row and col
109 * @exception IndexOutOfBoundsException if <code>row</code> is less than
110 * zero or greater than the number of rows minus 1, or if
111 * <code>col</code> is less than 0 or greater than the number of
112 * columns minus 1.
113 */
114 public void set(int row, int col, int value) {
115 checkIndices(row, col);
116 elements[row][col] = value;
117 }
118
119 /**
120 * Returns the number of rows in this matrix.
121 *
122 * @return number of rows in this <code>Matrix</code>
123 */
124 public int getRows() {
125 return rowCount;
126 }
127
128 /**
129 * Returns the number of cols in this matrix.
130 *
131 * @return number of columns in this <code>Matrix</code>
132 */
133 public int getCols() {
134 return colCount;
135 }
136
137 /**
138 * Clones this object.
139 *
140 * @return A clone of this <code>Matrix</code>
141 */
142 public Object clone() {
143 try {
144 Matrix clone = (Matrix) super.clone();
145 clone.elements = (int[][]) elements.clone();
146 return clone;
147 }
148 catch (CloneNotSupportedException e) {
149 // Can't happen
150 throw new InternalError();
151 }
152 }
153
154 /**
155 * Compares passed <CODE>Matrix</CODE> to this <code>Matrix</code> for
156 * equality. Two <code>Matrix</code> objects are semantically equal if
157 * they have the same order (i.e., same number of rows and columns), and
158 * the <code>int</code> value of each element in this <code>Matrix</code>
159 * is equal to the corresponding <code>int</code> value in the passed
160 * <code>Matrix</code>.
161 *
162 * @param An object to compare to this <code>Matrix</code>
163 * @return <code>true</code> if this <code>Matrix</code> is semantically
164 * equal to the passed <code>Matrix</code>
165 */
166 public boolean equals(Object o) {
167
168 if ((o == null) || (getClass() != o.getClass())) {
169 return false;
170 }
171
172 // This can't fail because the class of o is exactly Matrix
,
173 // as was proven when (getClass() != o.getClass()) returned false
174 Matrix m = (Matrix) o;
175
176 // Because this class extends Object, don't call super.equals()
177
178 // To be semantically equal, both matrices must have the same order
179 if ((rowCount != m.rowCount) || (colCount != m.colCount)) {
180 return false;
181 }
182
183 // To be semantically equal, corresponding elements of both
184 // matrices must be equal
185 for (int row = 0; row < rowCount; ++row) {
186 for (int col = 0; col < colCount; ++col) {
187
188 if (elements[row][col] != m.elements[row][col]) {
189 return false;
190 }
191 }
192 }
193
194 return true;
195 }
196
197 /**
198 * Computes the hash code for this <code>Matrix</code>.
199 *
200 * @return a hashcode value for this <code>Matrix</code>
201 */
202 public int hashcode() {
203
204 int retVal = rowCount * colCount;
205
206 for (int row = 0; row < rowCount; ++row) {
207 for (int col = 0; col < colCount; ++col) {
208
209 retVal ^= elements[row][col];
210 }
211 }
212
213 return retVal;
214 }
215 /**
216 * Ensures passed two-dimensional array is valid for initializing a
217 * <CODE>Matrix</CODE> object.
218 */
219 private static void checkValidity(int[][] val) {
220
221 try {
222 int rows = val.length;
223 if (rows == 0) {
224 throw new IllegalArgumentException();
225 }
226 int cols = val[0].length;
227 if (cols == 0) {
228 throw new IllegalArgumentException();
229 }
230 for (int i = 1; i < rows; ++i) {
231 if (val[i].length != cols) {
232 throw new IllegalArgumentException();
233 }
234 }
235 }
236 catch (NullPointerException e) {
237 throw new IllegalArgumentException();
238 }
239 }
240
241 /**
242 * Ensures passed row and column represent valid indices into this
243 * <CODE>Matrix</CODE>.
244 */
245 private void checkIndices(int row, int col) {
246 if (row >= rowCount || row < 0 || col >= colCount || col < 0) {
247 throw new IndexOutOfBoundsException();
248 }
249 }
250 }
1 package com.artima.examples.matrix.ex1;
2
3 class Example1 {
4
5 public static void main(String[] args) {
6
7 int[][] init1 = { {2, 2}, {2, 2} };
8 int[][] init2 = { {1, 2}, {3, 4} };
9
10 Matrix m1 = new Matrix(init1);
11 Matrix m2 = new Matrix(init2);
12
13 // Add m1 & m2, store result in a new Matrix object
14 Matrix sum = new Matrix(2, 2);
15 for (int i = 0; i < 2; ++i) {
16 for (int j = 0; j < 2; ++j) {
17 int addend1 = m1.get(i, j);
18 int addend2 = m2.get(i, j);
19 sum.set(i, j, addend1 + addend2);
20 }
21 }
22
23 // Print out the sum
24 System.out.print("Sum: {");
25 for (int i = 0; i < 2; ++i) {
26 for (int j = 0; j < 2; ++j) {
27 int val = sum.get(i, j);
28 System.out.print(val);
29 if (i == 0 || j == 0) {
30 System.out.print(", ");
31 }
32 }
33 }
34 System.out.println("}");
35
36 }
37 }
set()
method replaced by service-oriented methods
1 package com.artima.examples.matrix.ex2; 2 3 import java.io.Serializable; 4 5 /** 6 * A two-dimensional matrix of <CODE>int</CODE>s. 7 * 8 * <P> 9 * The <em>order</em> of the matrix is its number of rows and columns. For 10 * example, the order of a matrix with 5 rows and 4 columns is "5 by 4." A 11 * matrix with the same number of rows and columns, such as a 3 by 3 matrix, 12 * is a <em>square matrix</em>. A matrix all of whose elements is zero is a 13 * <em>zero matrix</em>. 14 * 15 * <P> 16 * Instances of <CODE>Matrix</CODE> are immutable. 17 * 18 * @author Bill Venners 19 */ 20 public class Matrix implements Serializable, Cloneable { 21 22 private int[][] elements; 23 private int rowCount; 24 private int colCount; 25 26 /** 27 * Construct a new square <code>Matrix</code> whose order is determined 28 * by the passed number of rows. Yields a zero matrix, i.e., all elements 29 * of the new <CODE>Matrix</CODE> will be initialized to zero. 30 * 31 * @param rows The number of rows and columns in the new square 32 * <CODE>Matrix</CODE> 33 * @exception IllegalArgumentException if <code>rows</code> is less than 34 * one 35 */ 36 public Matrix(int rows) { 37 38 if (rows < 1) { 39 throw new IllegalArgumentException(); 40 } 41 42 elements = new int[rows][rows]; 43 rowCount = rows; 44 colCount = rows; 45 } 46 47 /** 48 * Construct a new <EM>zero matrix</EM> whose order is determined by the 49 * passed number of rows and columns. The order is (rows by columns). 50 * Yields a zero matrix, i.e., all elements of the new 51 * <CODE>Matrix</CODE> will be initialized to zero. 52 * 53 * @param rows The number of rows in the new <CODE>Matrix</CODE> 54 * @param cols The number of columns in the new <CODE>Matrix</CODE> 55 * @exception IllegalArgumentException if <code>rows</code> or 56 * <code>cols</code> is less than 1 57 */ 58 public Matrix(int rows, int cols) { 59 60 if (rows < 1 || cols < 1) { 61 throw new IllegalArgumentException(); 62 } 63 64 elements = new int[rows][cols]; 65 rowCount = rows; 66 colCount = cols; 67 } 68 69 /** 70 * Construct a new <CODE>Matrix</CODE> whose elements will be initialized 71 * with values from the passed two-dimensional array of 72 * <CODE>int</CODE>s. The order of the matrix will be determined by the 73 * sizes of the passed arrays. For example, a two dimensional array 74 * constructed with <CODE>new int[4][9]</CODE>, would yield a matrix 75 * whose order is 4 by 9. The lengths of each of the arrays held from the 76 * initial array must be the same. The two-dimensional array passed as 77 * <CODE>init</CODE> will not be used as part of the state of the newly 78 * constructed <CODE>Matrix</CODE> object. 79 * 80 * @param init A two-dimensional array of <code>int</code>s with which 81 * to initialize the new <code>Matrix</code> 82 * @param cols The number of columns in the new <CODE>Matrix</CODE> 83 * @exception IllegalArgumentException if the length of any passed array 84 * is zero, or if the length of all the secondary arrays are not 85 * equivalent. 86 */ 87 public Matrix(int[][] init) { 88 89 checkValidity(init); 90 91 elements = (int[][]) init.clone(); 92 rowCount = init.length; 93 colCount = init[0].length; 94 } 95 96 /** 97 * Returns the element value at the specified row and column. 98 * 99 * @param row The row of the element whose value is to be returned 100 * @param col The column of the element whose value is to be returned 101 * @return value of element at specified row and column 102 * @exception IndexOutOfBoundsException if <code>row</code> is less than 103 * zero or greater than the number of rows minus 1, or if 104 * <code>col</code> is less than 0 or greater than the number of 105 * columns minus 1. 106 */ 107 public int get(int row, int col) { 108 109 if (row >= rowCount || row < 0 || col >= colCount || col < 0) { 110 throw new IndexOutOfBoundsException(); 111 } 112 113 return elements[row][col]; 114 } 115 116 /** 117 * Returns the number of rows in this <code>Matrix</code>. 118 * 119 * @return number of rows in this <code>Matrix</code> 120 */ 121 public int getRows() { 122 return rowCount; 123 } 124 125 /** 126 * Returns the number of columns in this <code>Matrix</code>. 127 * 128 * @return number of columns in this <code>Matrix</code> 129 */ 130 public int getCols() { 131 return colCount; 132 } 133 134 /** 135 * Adds the passed <code>Matrix</code> to this one. The order of the 136 * passed <code>Matrix</code> must be identical to the order of this 137 * <code>Matrix</code>. 138 * 139 * <P> 140 * The sum of two <code>Matrix</code> objects is a <code>Matrix</code> of 141 * the same order of the two addends. Each element of the sum 142 * <code>Matrix</code> is equal to the sum of the corresponding elements 143 * in the <code>Matrix</code> addends. For example: 144 * 145 * <PRE> 146 * | 1 2 3 | | 9 -8 7 | | 10 -6 10 | 147 * | 4 5 6 | + | -6 5 -4 | = | -2 10 2 | 148 * | 7 8 9 | | -3 2 -1 | | 4 10 8 | 149 * </PRE> 150 * 151 * <P> 152 * This method does not throw any exception on overflow. 153 * 154 * @param addend the <code>Matrix</code> to add to this one 155 * @return The sum of this <code>Matrix</code> and the passed 156 * <code>Matrix</code> 157 * @exception IllegalArgumentException if the order of the passed 158 * <code>Matrix</code> object differs from the order of this 159 * <code>Matrix</code> 160 */ 161 public Matrix add(Matrix addend) { 162 163 // Make sure addend has the same order as this matrix 164 if ((addend.rowCount != rowCount) 165 || (addend.colCount != colCount)) { 166 167 throw new IllegalArgumentException(); 168 } 169 170 Matrix retVal = new Matrix(elements); 171 for (int row = 0; row < rowCount; ++row) { 172 for (int col = 0; col < colCount; ++col) { 173 retVal.elements[row][col] += addend.elements[row][col]; 174 } 175 } 176 return retVal; 177 } 178 179 /** 180 * Subtracts the passed <code>Matrix</code> from this one. The order of 181 * the passed <code>Matrix</code> must be identical to the order of this 182 * <code>Matrix</code>. Returned <code>Matrix</code> equals the sum of 183 * this <code>Matrix</code> and the negation of the passed 184 * <code>Matrix</code>. 185 * 186 * <P> 187 * The difference of two <code>Matrix</code> objects is a 188 * <code>Matrix</code> of the same order of the minuend and subtrahend. 189 * Each element of the sum <code>Matrix</code> is equal to the difference 190 * of the corresponding elements in the minuend (this) and subtrahend 191 * (passed) <code>Matrix</code> objects. For example: 192 * 193 * <PRE> 194 * | 1 2 3 | | 9 -8 7 | | -8 10 -4 | 195 * | 4 5 6 | - | -6 5 -4 | = | 10 0 10 | 196 * | 7 8 9 | | -3 2 -1 | | 10 6 10 | 197 * </PRE> 198 * 199 * <P> 200 * This method does not throw any exception on overflow. 201 * 202 * @param subtrahend the <code>Matrix</code> to subtract from this one 203 * @return The difference of this <code>Matrix</code> and the passed 204 * <code>Matrix</code> 205 * @exception IllegalArgumentException if the order of the passed 206 * <code>Matrix</code> object differs from the order of this 207 * <code>Matrix</code> 208 */ 209 public Matrix subtract(Matrix subtrahend) { 210 211 // To be subtracted, subtrahend must have the same order 212 if ((subtrahend.rowCount != rowCount) 213 || (subtrahend.colCount != colCount)) { 214 215 throw new IllegalArgumentException(); 216 } 217 218 Matrix retVal = new Matrix(elements); 219 for (int row = 0; row < rowCount; ++row) { 220 for (int col = 0; col < colCount; ++col) { 221 retVal.elements[row][col] -= subtrahend.elements[row][col]; 222 } 223 } 224 return retVal; 225 } 226 227 /** 228 * Multiplies this matrix by the passed scalar. Returns a new matrix 229 * representing the result of the multiplication. To negate a matrix, for 230 * example, just multiply it by -1. 231 * 232 * <P> 233 * The product of a <code>Matrix</code> and a scalar is a 234 * <code>Matrix</code> of the same order as the <code>Matrix</code> 235 * multiplicand. Each element of the product <code>Matrix</code> is equal 236 * to the product of the corresponding element in the <code>Matrix</code> 237 * multiplicand and the scalar multiplier. For example: 238 * 239 * <PRE> 240 * | 1 2 3 | | -2 -4 -6 | 241 * -2 * | 4 5 6 | = | -8 -10 -12 | 242 * | 7 8 9 | | -14 -16 -18 | 243 * </PRE> 244 * 245 * <P> 246 * This method does not throw any exception on overflow. 247 * 248 * @param addend the <code>Matrix</code> to add to this one 249 * @return The sum of this <code>Matrix</code> and the passed 250 * <code>Matrix</code> 251 * @exception IllegalArgumentException if the order of the passed 252 * <code>Matrix</code> object differs from the order of this 253 * <code>Matrix</code> 254 */ 255 public Matrix multiply(int scalar) { 256 257 Matrix retVal = new Matrix(elements); 258 for (int row = 0; row < rowCount; ++row) { 259 for (int col = 0; col < colCount; ++col) { 260 retVal.elements[row][col] *= scalar; 261 } 262 } 263 return retVal; 264 } 265 266 /** 267 * Multiplies this <code>Matrix</code> (the multiplicand) by the passed 268 * <code>Matrix</code> (the multiplier). The number of columns in this 269 * multiplicand <code>Matrix</code> must equal the number rows in the 270 * passed multiplier <code>Matrix</code>. 271 * 272 * <P> 273 * The product of two <code>Matrix</code> objects is a 274 * <code>Matrix</code> that has the same number of rows as the 275 * multiplicand (this <code>Matrix</code>) and the same number of columns 276 * as the multiplier (passed <code>Matrix</code>). Each element of the 277 * product <code>Matrix</code> is equal to sum of the products of the 278 * elements of corresponding multiplicand row and multiplier column. 279 * For example: 280 * 281 * <PRE> 282 * | 0 1 | | 6 7 | | (0*6 + 1*8) (0*7 + 1*9) | | 8 9 | 283 * | 2 3 | * | 8 9 | = | (2*6 + 3*8) (2*7 + 3*9) | = | 36 41 | 284 * | 4 5 | | (4*6 + 5*8) (4*7 + 5*9) | | 64 73 | 285 * </PRE> 286 * 287 * <P> 288 * This method does not throw any exception on overflow. 289 * 290 * @param multiplier the <code>Matrix</code> to multiply to this one 291 * @return A new <code>Matrix</code> representing the product of this 292 * <code>Matrix</code> and the passed <code>Matrix</code> 293 * @exception IllegalArgumentException if the number of rows of the 294 * passed <code>Matrix</code> object differs from the number of 295 * columns of this <code>Matrix</code> 296 */ 297 public Matrix multiply(Matrix multiplier) { 298 299 // To do a matrix multiplication, the number of columns in this 300 // matrix must equal the number of rows of the passed multiplicand. 301 if (colCount != multiplier.rowCount) { 302 throw new IllegalArgumentException(); 303 } 304 305 // Calculate order of result 306 int resultRows = rowCount; 307 int resultCols = multiplier.colCount; 308 309 // Create array for result 310 int[][] resultArray = new int[resultRows][resultCols]; 311 312 Matrix retVal = new Matrix(elements); 313 314 for (int row = 0; row < resultRows; ++row) { 315 for (int col = 0; col < resultCols; ++col) { 316 for (int i = 0; i < colCount; ++i) { 317 318 resultArray[row][col] += elements[row][i] 319 * multiplier.elements[i][col]; 320 } 321 } 322 } 323 return retVal; 324 } 325 326 /** 327 * Returns a <code>String</code> that contains the integer values of the 328 * elements of this <code>Matrix</code>. Each row of element values is 329 * enclosed in parentheses and separated by commas, and the entire result 330 * is enclosed in a set of parentheses. For example, for the matrix: 331 * 332 * <PRE> 333 * | 1 2 3 | 334 * | 4 5 6 | 335 * | 7 8 9 | 336 * </PRE> 337 * 338 * This method would return the string: 339 * 340 * <PRE> 341 * ((1, 2, 3), (4, 5, 6), (7, 8, 9)) 342 * </PRE> 343 * 344 * @return A new <code>String</code> representation of the state of this 345 * <code>Matrix</code> 346 */ 347 public String toString() { 348 349 StringBuffer retVal = new StringBuffer("("); 350 351 for (int row = 0; row < rowCount; ++row) { 352 retVal.append("("); 353 for (int col = 0; col < colCount; ++col) { 354 retVal.append(elements[row][col]); 355 if (col != colCount - 1) { 356 retVal.append(", "); 357 } 358 } 359 retVal.append(")"); 360 if (row != rowCount - 1) { 361 retVal.append(", "); 362 } 363 } 364 retVal.append(")"); 365 return retVal.toString(); 366 } 367 368 /** 369 * Clones this object. 370 * 371 * @return A clone of this <code>Matrix</code> 372 */ 373 public Object clone() { 374 try { 375 Matrix clone = (Matrix) super.clone(); 376 clone.elements = (int[][]) elements.clone(); 377 return clone; 378 } 379 catch (CloneNotSupportedException e) { 380 // Can't happen 381 throw new InternalError(); 382 } 383 } 384 385 /** 386 * Compares passed <CODE>Matrix</CODE> to this <code>Matrix</code> for 387 * equality. Two <code>Matrix</code> objects are semantically equal if 388 * they have the same order (i.e., same number of rows and columns), and 389 * the <code>int</code> value of each element in this <code>Matrix</code> 390 * is equal to the corresponding <code>int</code> value in the passed 391 * <code>Matrix</code>. 392 * 393 * @param An object to compare to this <code>Matrix</code> 394 * @return <code>true</code> if this <code>Matrix</code> is semantically 395 * equal to the passed <code>Matrix</code> 396 */ 397 public boolean equals(Object o) { 398 399 if ((o == null) || (getClass() != o.getClass())) { 400 return false; 401 } 402 403 Matrix m = (Matrix) o; 404 405 // Because this class extends Object, don't 406 // call super.equals() 407 408 // To be semantically equal, both matrices must 409 // have the same order 410 if ((rowCount != m.rowCount) || (colCount != m.colCount)) { 411 return false; 412 } 413 414 // To be semantically equal, corresponding 415 // elements of both matrices must be equal 416 for (int row = 0; row < rowCount; ++row) { 417 for (int col = 0; col < colCount; ++col) { 418 419 if (elements[row][col] != m.elements[row][col]) { 420 return false; 421 } 422 } 423 } 424 425 return true; 426 } 427 428 /** 429 * Computes the hash code for this <code>Matrix</code>. 430 * 431 * @return a hashcode value for this <code>Matrix</code> 432 */ 433 public int hashcode() { 434 435 int retVal = rowCount * colCount; 436 437 for (int row = 0; row < rowCount; ++row) { 438 for (int col = 0; col < colCount; ++col) { 439 440 retVal *= elements[row][col]; 441 } 442 } 443 444 return retVal; 445 } 446 447 /** 448 * Ensures passed two-dimensional array is valid for initializing a 449 * <CODE>Matrix</CODE> object. 450 */ 451 private static void checkValidity(int[][] val) { 452 453 try { 454 int rows = val.length; 455 if (rows == 0) { 456 throw new IllegalArgumentException(); 457 } 458 int cols = val[0].length; 459 if (cols == 0) { 460 throw new IllegalArgumentException(); 461 } 462 for (int i = 1; i < rows; ++i) { 463 if (val[i].length != cols) { 464 throw new IllegalArgumentException(); 465 } 466 } 467 } 468 catch (NullPointerException e) { 469 throw new IllegalArgumentException(); 470 } 471 } 472 } 1 package com.artima.examples.matrix.ex2; 2 3 class Example2 { 4 5 public static void main(String[] args) { 6 7 int[][] init1 = { {2, 2}, {2, 2} }; 8 int[][] init2 = { {1, 2}, {3, 4} }; 9 10 Matrix m1 = new Matrix(init1); 11 Matrix m2 = new Matrix(init2); 12 13 // Add m1 & m2, store result in a new matrix object 14 Matrix sum = m1.add(m2); 15 16 // Print out the sum 17 System.out.println("Sum: " + sum.toString()); 18 } 19 }
Matrix
to add()
to itself
set()
and get()
methods are not evil
get
and set
,
code that manipulates that
data gets spread across the program.
1 package com.artima.examples.stampdispenser.ex1; 2 3 import java.util.Set; 4 import java.util.Iterator; 5 import java.util.HashSet; 6 7 /** 8 * A stamp dispenser that accepts nickels and dimes and dispenses twenty cent 9 * stamps. 10 * 11 * @author Bill Venners 12 */ 13 public class StampDispenser { 14 15 private final static int STAMP_VALUE = 20; 16 private int balance; 17 private Set listeners = new HashSet(); 18 19 /** 20 * Constructs a new stamp dispenser with a starting balance of zero. 21 */ 22 public StampDispenser() { 23 } 24 25 /** 26 * Adds the specified stamp dispenser listener to receive stamp dispenser 27 * events from this stamp dispenser. If <code>l</code> is 28 * <code>null</code>, no exception is thrown and no action is performed. 29 * If <code>l</code> is already registered as a listener, no action is 30 * performed. 31 */ 32 public synchronized void addStampDispenserListener( 33 StampDispenserListener l) { 34 35 listeners.add(l); 36 } 37 38 /** 39 * Removes the specified stamp dispenser listener so that it no longer 40 * receives stamp dispenser events from this stamp dispenser. This method 41 * performs no function, nor does it throw an exception, if the listener 42 * specified by the argument was not previously added to this component. 43 * If <code>l</code> is <code>null</code>, no exception is thrown and no 44 * action is performed. 45 */ 46 public synchronized void removeStampDispenserListener( 47 StampDispenserListener l) { 48 49 listeners.remove(l); 50 } 51 52 /** 53 * Add either 5 or 10 cents to the stamp dispenser. If the amount added 54 * causes the balance to become or exceed 20 cents, the price of a stamp, 55 * the stamp will be automatically dispensed. If the stamp is dispensed, 56 * the amount of the balance after the stamp is dispensed is returned to 57 * the client. 58 * 59 * @throws IllegalArgumentException if passed <code>amount</code> doesn't 60 * equal either 5 or 10 61 */ 62 public synchronized void add(int amount) { 63 64 if ((amount != 5) && (amount != 10)) { 65 throw new IllegalArgumentException(); 66 } 67 68 balance += amount; 69 70 if (balance >= STAMP_VALUE) { 71 72 // Dispense a stamp and return any change 73 // balance - STAMP_VALUE is amount in excess of twenty cents 74 // (the stamp price) to return as change. After dispensing the 75 // stamp and returning any change, the new balance will be zero. 76 StampDispenserEvent event = new StampDispenserEvent(this, 77 balance - STAMP_VALUE, 0); 78 balance = 0; 79 fireStampDispensed(event, listeners); 80 } 81 else { 82 83 // Fire an event to indicate the balance has increased 84 StampDispenserEvent event = new StampDispenserEvent(this, 85 amount, balance); 86 fireCoinAccepted(event, listeners); 87 } 88 } 89 90 /** 91 * Returns coins. If the balance is zero, no action is performed. 92 */ 93 public synchronized void returnCoins() { 94 95 // Make sure balance is greater than zero, because no event should 96 // be fired if the coin return lever is pressed when the stamp 97 // dispenser has a zero balance 98 if (balance > 0) { 99 100 // Return the entire balance to the client 101 StampDispenserEvent event = new StampDispenserEvent(this, 102 balance, 0); 103 balance = 0; 104 fireCoinsReturned(event, listeners); 105 } 106 } 107 108 /** 109 * Helper method that fires coinAccepted events. 110 * 111 * @param event <code>StampDispenserEvent</code> to propagate 112 * @param listeners <code>Set</code> containing zero to many (and only) 113 * <code>StampDispenserListener</code>s 114 */ 115 private static void fireCoinAccepted(StampDispenserEvent event, 116 Set listeners) { 117 118 Iterator it = listeners.iterator(); 119 while (it.hasNext()) { 120 StampDispenserListener l = (StampDispenserListener) it.next(); 121 l.coinAccepted(event); 122 } 123 } 124 125 /** 126 * Helper method that fires stampDispensed events. 127 * 128 * @param event <code>StampDispenserEvent</code> to propagate 129 * @param listeners <code>Set</code> containing zero to many (and only) 130 * <code>StampDispenserListener</code>s 131 */ 132 private static void fireStampDispensed(StampDispenserEvent event, 133 Set listeners) { 134 135 Iterator it = listeners.iterator(); 136 while (it.hasNext()) { 137 StampDispenserListener l = (StampDispenserListener) it.next(); 138 l.stampDispensed(event); 139 } 140 } 141 142 /** 143 * Helper method that fires coinsReturned events. 144 * 145 * @param event <code>StampDispenserEvent</code> to propagate 146 * @param listeners <code>Set</code> containing zero to many (and only) 147 * <code>StampDispenserListener</code>s 148 */ 149 private static void fireCoinsReturned(StampDispenserEvent event, 150 Set listeners) { 151 152 Iterator it = listeners.iterator(); 153 while (it.hasNext()) { 154 StampDispenserListener l = (StampDispenserListener) it.next(); 155 l.coinsReturned(event); 156 } 157 } 158 } 1 package com.artima.examples.stampdispenser.ex1; 2 3 import java.util.EventObject; 4 5 /** 6 * Event that indicates a stamp dispenser has performed an action. The three 7 * kinds of actions that cause a stamp dispenser event to be propagated are: 8 * (1) accepting a coin, (2) dispensing a stamp, (3) returning coins. 9 * 10 * @author Bill Venners 11 */ 12 public class StampDispenserEvent extends java.util.EventObject { 13 14 private int amountReturned; 15 private int balance; 16 17 /** 18 * Constructs a <code>StampDispenserEvent</code> with 19 * <code>amountReturned</code>, and <code>balance</code>. 20 * 21 * @param amountReturned the amount of money, if any, returned to the 22 * client, either as the result of a coin return or as change when 23 * dispensing a stamp. 24 * @param balance the amount of money, if any, remaining as the current 25 * balance of the stamp dispenser after this event has occurred. 26 * @throws IllegalArgumentException if balance is not one of 0, 5, 10, or 27 * 15; or if amountReturned is not one of 0, 5, 10, or 15. 28 */ 29 public StampDispenserEvent(StampDispenser source, int amountReturned, 30 int balance) { 31 32 super(source); 33 34 if (balance != 0 && balance != 5 && balance != 10 35 && balance != 15) { 36 37 throw new IllegalArgumentException(); 38 } 39 40 if (amountReturned != 0 && amountReturned != 5 41 && amountReturned != 10 && amountReturned != 15) { 42 43 throw new IllegalArgumentException(); 44 } 45 46 this.amountReturned = amountReturned; 47 this.balance = balance; 48 } 49 50 /** 51 * Returns the amount of money returned to the client, expressed in units 52 * of American pennies. 53 */ 54 public int getAmountReturned() { 55 return amountReturned; 56 } 57 58 /** 59 * Returns the current balance: the amount of money that has been 60 * inserted into the stamp dispenser, but not returned via a coin return 61 * or consumed in exchange for a dispensed stamp. For example, if the 62 * <code>balance</code> is zero and a nickel is added, the 63 * <code>balance</code> in the resulting stamp dispenser event will be 5. 64 * If another dime is added, the <code>balance</code> in the resulting 65 * stamp dispenser event will be 15. If the <code>returnCoins</code> 66 * method is then invoked on the stamp dispenser, the 67 * <code>balance</code> of the resulting stamp dispenser event will be 0. 68 */ 69 public int getBalance() { 70 return balance; 71 } 72 } 1 package com.artima.examples.stampdispenser.ex1; 2 3 /** 4 * Listener interface for receiving stamp dispenser events. 5 * 6 * @author Bill Venners 7 */ 8 public interface StampDispenserListener { 9 10 /** 11 * Invoked when a stamp has been dispensed. If coins have also been 12 * returned as change, the amount is indicated by the return value of 13 * <CODE>getReturnedAmount</CODE> method of the passed 14 * <code>StampDispenserEvent</code>. 15 */ 16 void stampDispensed(StampDispenserEvent e); 17 18 /** 19 * Invoked when coins have been returned as the result of the 20 * <code>returnCoins</code> method being invoked on a 21 * <code>StampDispenser</code>. Coins that are returned as change when a 22 * stamp is dispensed are reported via the event passed to 23 * <code>stampDispensed</code>. 24 */ 25 void coinsReturned(StampDispenserEvent e); 26 27 /** 28 * Invoked when coins have been accepted but no stamp has been dispensed. 29 * A coin that causes a stamp to be dispensed does not generate a 30 * <code>coinsAccepted</code> method invocation, just a 31 * <code>stampDispensed</code> method invocation. 32 */ 33 void coinAccepted(StampDispenserEvent e); 34 }
get()
methods
package com.artima.examples.account.ex1; /** * Exception thrown byAccount
s to indicate that a requested * withdrawal has failed because of insufficient funds. */ public class InsufficientFundsException extends Exception { /** * Minimum additional balance required for the requested withdrawal to * succeed. */ private long shortfall; /** * Constructs anInsufficientFundsException
with the passed * shortfall and no specified detail message. * * @param shortfall the amount in excess of available funds that caused a * withdrawal request to fail. * @throws IllegalArgumentException if passed shortfall is less than or * equal to zero */ public InsufficientFundsException(long shortfall) { if (shortfall <= 0) { throw new IllegalArgumentException(); } this.shortfall = shortfall; } /** * Constructs anInsufficientFundsException
with the passed * detail message and shortfall. * * @param message the detail message * @param shortfall the amount in excess of available funds that caused a * withdrawal request to fail. * @throws IllegalArgumentException if passed shortfall is less than or * equal to zero */ public InsufficientFundsException(String message, long shortfall) { super(message); if (shortfall <= 0) { throw new IllegalArgumentException(); } this.shortfall = shortfall; } /** * Returns the shortfall that caused a withrawal request to fail. The * shortfall is the minimum additional balance required for the requested * withdrawal to succeed. * * @returns shortfall the amount in excess of available funds that caused * a withdrawal request to fail. */ public long getShortfall() { return shortfall; } }
1 package com.artima.examples.stampdispenser.ex1; 2 3 import java.util.EventObject; 4 5 /** 6 * Event that indicates a stamp dispenser has performed an action. The three 7 * kinds of actions that cause a stamp dispenser event to be propagated are: 8 * (1) accepting a coin, (2) dispensing a stamp, (3) returning coins. 9 * 10 * @author Bill Venners 11 */ 12 public class StampDispenserEvent extends java.util.EventObject { 13 14 private int amountReturned; 15 private int balance; 16 17 /** 18 * Constructs a <code>StampDispenserEvent</code> with 19 * <code>amountReturned</code>, and <code>balance</code>. 20 * 21 * @param amountReturned the amount of money, if any, returned to the 22 * client, either as the result of a coin return or as change when 23 * dispensing a stamp. 24 * @param balance the amount of money, if any, remaining as the current 25 * balance of the stamp dispenser after this event has occurred. 26 * @throws IllegalArgumentException if balance is not one of 0, 5, 10, or 27 * 15; or if amountReturned is not one of 0, 5, 10, or 15. 28 */ 29 public StampDispenserEvent(StampDispenser source, int amountReturned, 30 int balance) { 31 32 super(source); 33 34 if (balance != 0 && balance != 5 && balance != 10 35 && balance != 15) { 36 37 throw new IllegalArgumentException(); 38 } 39 40 if (amountReturned != 0 && amountReturned != 5 41 && amountReturned != 10 && amountReturned != 15) { 42 43 throw new IllegalArgumentException(); 44 } 45 46 this.amountReturned = amountReturned; 47 this.balance = balance; 48 } 49 50 /** 51 * Returns the amount of money returned to the client, expressed in units 52 * of American pennies. 53 */ 54 public int getAmountReturned() { 55 return amountReturned; 56 } 57 58 /** 59 * Returns the current balance: the amount of money that has been 60 * inserted into the stamp dispenser, but not returned via a coin return 61 * or consumed in exchange for a dispensed stamp. For example, if the 62 * <code>balance</code> is zero and a nickel is added, the 63 * <code>balance</code> in the resulting stamp dispenser event will be 5. 64 * If another dime is added, the <code>balance</code> in the resulting 65 * stamp dispenser event will be 15. If the <code>returnCoins</code> 66 * method is then invoked on the stamp dispenser, the 67 * <code>balance</code> of the resulting stamp dispenser event will be 0. 68 */ 69 public int getBalance() { 70 return balance; 71 } 72 }
1 /*
2 * This source code (.java) file is Copyright (C) 2000 Artima Software, Inc.
3 * All rights reserved. This file accompanies the Jini Place Service Draft
4 * Specification, written by Bill Venners and published on the World Wide
5 * Web at:
6 *
7 * http://www.artima.com/jini/cyberspace/DraftSpec.html,
8 *
9 * This source file may not be copied, modified, or redistributed EXCEPT as
10 * allowed by the following statements: From August 11, 2000 through
11 * December 31, 2000, you may copy and/or modify these files to test and
12 * experiment with the Place API, described in the Jini Place Service Draft
13 * Specification. Any bug fixes must be given back to Artima Software, Inc.
14 * You may not redistribute this file or any binary (such as .class) files
15 * generated from this file. You may not distribute modified versions this
16 * files or any binary (such as .class) files generated from modified
17 * versions of this file. You may not remove this copyright notice. You may
18 * not use this file in printed media without the express permission of Bill
19 * Venners. And if that weren't enough, you must destroy all copies of this
20 * file, and any binary (such as .class) files generated from this file, by
21 * December 31, 2000.
22 *
23 * ARTIMA SOFTWARE, INC. MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
24 * SUITABILITY OF THIS SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
25 * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
26 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. BILL VENNERS SHALL NOT BE LIABLE
27 * FOR ANY DAMAGES SUFFERED BY A LICENSEE AS A RESULT OF USING, MODIFYING OR
28 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
29 */
30 package net.artima.place;
31
32 import java.io.Serializable;
33
34 /**
35 * Associates a <CODE>Link</CODE> to a <CODE>ResourceInfo</CODE>. Keeping the
36 * <CODE>ResourceInfo</CODE> outside of the <CODE>Link</CODE>, enables
37 * modifiable places to more easily change the <CODE>ResourceInfo</CODE> data
38 * for a particular <CODE>Link</CODE>.
39 *
40 * @author Bill Venners
41 */
42 public class LinkItem implements Serializable {
43
44 private Link link;
45 private ResourceInfo resourceInfo;
46
47 /**
48 * Constructs a <CODE>LinkItem</CODE> with passed <CODE>Link</CODE> and
49 * <CODE>ResourceInfo</CODE>.
50 *
51 * @param link The <code>Link</code> to hold in this
52 * <code>LinkItem</code>
53 * @param resourceInfo The <code>ResourceInfo</code> to hold in this
54 * <code>LinkItem</code>
55 * @throws NullPointerException if the <code>Link</code> or
56 * <code>ResourceInfo</code> reference passed to this constructor is
57 * <code>null</code>
58 */
59 public LinkItem(Link link, ResourceInfo resourceInfo) {
60
61 if (link == null || resourceInfo == null) {
62 throw new NullPointerException();
63 }
64
65 this.link = link;
66 this.resourceInfo = resourceInfo;
67 }
68
69 /**
70 * Returns the <CODE>Link</CODE> object that's stored in this
71 * <CODE>LinkItem</CODE>.
72 *
73 * @return the <code>Link</code> held in this <code>LinkItem</code>
74 */
75 public Link getLink() {
76 return link;
77 }
78
79 /**
80 * Returns the <CODE>ResourceInfo</CODE> object that's stored in this
81 * <CODE>LinkItem</CODE>. The <CODE>ResourceInfo</CODE> provides
82 * information, suitable for display to users, about the linked-to
83 * resource.
84 *
85 * @return the <code>ResourceInfo</code> held in this
86 * <code>LinkItem</code>
87 */
88 public ResourceInfo getResourceInfo() {
89 return resourceInfo;
90 }
91
92 /**
93 * Compares the specified <CODE>Object</CODE> with this
94 * <CODE>LinkItem</CODE> for equality. Two <code>LinkItem</code>s are
95 * semantically equal if their <code>Link</code>s are semantically equal
96 * and their <code>ResourceInfo</code>s are semantically equal.
97 */
98 public boolean equals(Object o) {
99
100 if (o == null || (o.getClass() != getClass())) {
101 return false;
102 }
103
104 // This can't fail because the class o is exactly LinkItem
,
105 // as was proven when (getClass() != o.getClass()) returned false
106 LinkItem li = (LinkItem) o;
107
108 // Both Link and ResourceInfo must be semantically equal
109 if (!link.equals(li.link) || !resourceInfo.equals(li.resourceInfo)) {
110 return false;
111 }
112
113 return true;
114 }
115
116 /**
117 * Returns the hash code value for this <CODE>LinkItem</CODE>. The
118 * hashcode for a <code>LinkItem</code> is the exclusive OR of the
119 * hashcodes for the <code>LinkItem</code>'s constituent
120 * <code>Link</code> and <code>ResourceInfo</code>.
121 */
122 public int hashCode() {
123
124 return link.hashCode() ^ resourceInfo.hashCode();
125 }
126 }
127
HAS_0
, HAS_5
, HAS_10
,
HAS_15
add5
, add10
, returnCoins
dispenseStamp
, ret5
,
ret10
, ret15
Current State | Message | Action | Next State |
HAS_0 | add5 | HAS_5 | |
HAS_0 | add10 | HAS_10 | |
HAS_0 | returnCoins | HAS_0 | |
HAS_5 | add5 | HAS_10 | |
HAS_5 | add10 | HAS_15 | |
HAS_5 | returnCoins | ret5 | HAS_0 |
HAS_10 | add5 | HAS_15 | |
HAS_10 | add10 | dispenseStamp | HAS_0 |
HAS_10 | returnCoins | ret10 | HAS_0 |
HAS_15 | add5 | dispenseStamp | HAS_0 |
HAS_15 | add10 | dispenseStamp,ret5 | HAS_0 |
HAS_15 | returnCoins | ret15 | HAS_0 |
Initial State: HAS_0 |
1 package com.artima.examples.stampdispenser.ex2; 2 3 import java.util.Set; 4 import java.util.Iterator; 5 import java.util.HashSet; 6 7 /** 8 * A stamp dispenser that accepts nickels and dimes and dispenses twenty cent 9 * stamps. 10 * 11 * @author Bill Venners 12 */ 13 public class StampDispenser { 14 15 private static final int HAS_0 = 0; 16 private static final int HAS_5 = 1; 17 private static final int HAS_10 = 2; 18 private static final int HAS_15 = 3; 19 20 private int currentState = HAS_0; 21 private Set listeners = new HashSet(); 22 23 /** 24 * Constructs a new stamp dispenser with a starting balance of zero. 25 */ 26 public StampDispenser() { 27 } 28 29 /** 30 * Adds the specified stamp dispenser listener to receive stamp dispenser 31 * events from this stamp dispenser. If <code>l</code> is 32 * <code>null</code>, no exception is thrown and no action is performed. 33 * If <code>l</code> is already registered as a listener, no action is 34 * performed. 35 */ 36 public synchronized void addStampDispenserListener( 37 StampDispenserListener l) { 38 39 listeners.add(l); 40 } 41 42 /** 43 * Removes the specified stamp dispenser listener so that it no longer 44 * receives stamp dispenser events from this stamp dispenser. This method 45 * performs no function, nor does it throw an exception, if the listener 46 * specified by the argument was not previously added to this component. 47 * If <code>l</code> is <code>null</code>, no exception is thrown and no 48 * action is performed. 49 */ 50 public synchronized void removeStampDispenserListener( 51 StampDispenserListener l) { 52 53 listeners.remove(l); 54 } 55 56 /** 57 * Add 5 cents to the stamp dispenser. If the amount added causes the 58 * current value to become or exceed 20 cents, the price of a stamp, the 59 * stamp will be automatically dispensed. 60 */ 61 public synchronized void add5() { 62 63 switch (currentState) { 64 65 case HAS_0: 66 StampDispenserEvent event = new StampDispenserEvent(this, 0, 5); 67 fireCoinAccepted(event, listeners); 68 currentState = HAS_5; 69 break; 70 71 case HAS_5: 72 event = new StampDispenserEvent(this, 0, 10); 73 fireCoinAccepted(event, listeners); 74 currentState = HAS_10; 75 break; 76 77 case HAS_10: 78 event = new StampDispenserEvent(this, 0, 15); 79 fireCoinAccepted(event, listeners); 80 currentState = HAS_15; 81 break; 82 83 case HAS_15: 84 85 event = new StampDispenserEvent(this, 0, 0); 86 fireStampDispensed(event, listeners); 87 currentState = HAS_0; 88 break; 89 } 90 } 91 92 /** 93 * Add 10 cents to the stamp dispenser. If the amount added causes the 94 * current value to become or exceed 20 cents, the price of a stamp, the 95 * stamp will be automatically dispensed. 96 */ 97 public synchronized void add10() { 98 99 switch (currentState) { 100 101 case HAS_0: 102 StampDispenserEvent event = new StampDispenserEvent(this, 103 0, 10); 104 fireCoinAccepted(event, listeners); 105 currentState = HAS_10; 106 break; 107 108 case HAS_5: 109 event = new StampDispenserEvent(this, 0, 15); 110 fireCoinAccepted(event, listeners); 111 currentState = HAS_15; 112 break; 113 114 case HAS_10: 115 event = new StampDispenserEvent(this, 0, 0); 116 fireStampDispensed(event, listeners); 117 currentState = HAS_0; 118 break; 119 120 case HAS_15: 121 122 event = new StampDispenserEvent(this, 5, 0); 123 fireStampDispensed(event, listeners); 124 currentState = HAS_0; 125 break; 126 } 127 } 128 129 /** 130 * Returns coins. If the balance is zero, no action is performed. 131 */ 132 public synchronized void returnCoins() { 133 134 switch (currentState) { 135 136 case HAS_0: 137 currentState = HAS_0; 138 break; 139 140 case HAS_5: 141 StampDispenserEvent event = new StampDispenserEvent(this, 5, 0); 142 fireCoinsReturned(event, listeners); 143 currentState = HAS_0; 144 break; 145 146 case HAS_10: 147 event = new StampDispenserEvent(this, 10, 0); 148 fireCoinsReturned(event, listeners); 149 currentState = HAS_0; 150 break; 151 152 case HAS_15: 153 154 event = new StampDispenserEvent(this, 15, 0); 155 fireCoinsReturned(event, listeners); 156 currentState = HAS_0; 157 break; 158 } 159 } 160 161 /** 162 * Helper method that fires coinAccepted events. 163 * 164 * @param event <code>StampDispenserEvent</code> to propagate 165 * @param listeners <code>Set</code> containing zero to many (and only) 166 * <code>StampDispenserListener</code>s 167 */ 168 private static void fireCoinAccepted(StampDispenserEvent event, 169 Set listeners) { 170 171 Iterator it = listeners.iterator(); 172 while (it.hasNext()) { 173 StampDispenserListener l = (StampDispenserListener) it.next(); 174 l.coinAccepted(event); 175 } 176 } 177 178 /** 179 * Helper method that fires stampDispensed events. 180 * 181 * @param event <code>StampDispenserEvent</code> to propagate 182 * @param listeners <code>Set</code> containing zero to many (and only) 183 * <code>StampDispenserListener</code>s 184 */ 185 private static void fireStampDispensed(StampDispenserEvent event, 186 Set listeners) { 187 188 Iterator it = listeners.iterator(); 189 while (it.hasNext()) { 190 StampDispenserListener l = (StampDispenserListener) it.next(); 191 l.stampDispensed(event); 192 } 193 } 194 195 /** 196 * Helper method that fires coinsReturned events. 197 * 198 * @param event <code>StampDispenserEvent</code> to propagate 199 * @param listeners <code>Set</code> containing zero to many (and only) 200 * <code>StampDispenserListener</code>s 201 */ 202 private static void fireCoinsReturned(StampDispenserEvent event, 203 Set listeners) { 204 205 Iterator it = listeners.iterator(); 206 while (it.hasNext()) { 207 StampDispenserListener l = (StampDispenserListener) it.next(); 208 l.coinsReturned(event); 209 } 210 } 211 }
1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 import java.util.HashSet; 5 6 /** 7 * A stamp dispenser that accepts nickels and dimes and dispenses twenty cent 8 * stamps. 9 * 10 * @author Bill Venners 11 */ 12 public class StampDispenser { 13 14 private State currentState = Has0State.getState(); 15 private Set listeners = new HashSet(); 16 17 /** 18 * Constructs a new stamp dispenser with a starting balance of zero. 19 */ 20 public StampDispenser() { 21 } 22 23 /** 24 * Adds the specified stamp dispenser listener to receive stamp dispenser 25 * events from this stamp dispenser. If <code>l</code> is 26 * <code>null</code>, no exception is thrown and no action is performed. 27 * If <code>l</code> is already registered as a listener, no action is 28 * performed. 29 */ 30 public synchronized void addStampDispenserListener( 31 StampDispenserListener l) { 32 33 listeners.add(l); 34 } 35 36 /** 37 * Removes the specified stamp dispenser listener so that it no longer 38 * receives stamp dispenser events from this stamp dispenser. This method 39 * performs no function, nor does it throw an exception, if the listener 40 * specified by the argument was not previously added to this component. 41 * If <code>l</code> is <code>null</code>, no exception is thrown and no 42 * action is performed. 43 */ 44 public synchronized void removeStampDispenserListener( 45 StampDispenserListener l) { 46 47 listeners.remove(l); 48 } 49 50 /** 51 * Add 5 cents to the stamp dispenser. If the amount added causes the 52 * current value to become or exceed 20 cents, the price of a stamp, the 53 * stamp will be automatically dispensed. 54 */ 55 public void add5() { 56 57 currentState = currentState.add5(this, listeners); 58 } 59 60 /** 61 * Add 10 cents to the stamp dispenser. If the amount added causes the 62 * current value to become or exceed 20 cents, the price of a stamp, the 63 * stamp will be automatically dispensed. 64 */ 65 public void add10() { 66 67 currentState = currentState.add10(this, listeners); 68 } 69 70 /** 71 * Returns coins. If the balance is zero, no action is performed. 72 */ 73 public void returnCoins() { 74 75 currentState = currentState.returnCoins(this, listeners); 76 } 77 } 1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Iterator; 4 import java.util.Set; 5 6 /** 7 * Abstract superclass for all stamp dispenser state classes. 8 * 9 * The state machine that embodies the behavior of the stamp dispenser (which 10 * determines the behavior of the <CODE>State</code> subclasses) is described 11 * in this <a href="../../../../../statemachine.html">state transition 12 * table</a>. 13 * 14 * @author Bill Venners 15 */ 16 abstract class State { 17 18 /** 19 * Performs actions appropriate for the state represented by the class of 20 * this object for the add5 message. Returns a reference to the state 21 * object that represents the next state to transition to as a result of 22 * the arrival of this add5 message. 23 * 24 * @param stampDispenser the <code>StampDispenser</code> whose state this 25 * object represents 26 * @param listeners <code>Set</code> containing zero to many (and only) 27 * <code>StampDispenserListener</code>s 28 */ 29 abstract State add5(StampDispenser stampDispenser, Set listeners); 30 31 /** 32 * Performs actions appropriate for the state represented by the class of 33 * this object for the add10 message. Returns a reference to the state 34 * object that represents the next state to transition to as a result of 35 * the arrival of this add10 message. 36 * 37 * @param stampDispenser the <code>StampDispenser</code> whose state this 38 * object represents 39 * @param listeners <code>Set</code> containing zero to many (and only) 40 * <code>StampDispenserListener</code>s 41 */ 42 abstract State add10(StampDispenser stampDispenser, Set listeners); 43 44 /** 45 * Performs actions appropriate for the state represented by the class of 46 * this object for the returnCoins message. Returns a reference to the 47 * state object that represents the next state to transition to as a 48 * result of the arrival of this returnCoins message. 49 * 50 * @param stampDispenser the <code>StampDispenser</code> whose state this 51 * object represents 52 * @param listeners <code>Set</code> containing zero to many (and only) 53 * <code>StampDispenserListener</code>s 54 */ 55 abstract State returnCoins(StampDispenser stampDispenser, 56 Set listeners); 57 58 /** 59 * Helper method that fires coinAccepted events. 60 * 61 * @param event <code>StampDispenserEvent</code> to propagate 62 * @param listeners <code>Set</code> containing zero to many (and only) 63 * <code>StampDispenserListener</code>s 64 */ 65 static void fireCoinAccepted(StampDispenserEvent event, Set listeners) { 66 67 Iterator it = listeners.iterator(); 68 while (it.hasNext()) { 69 StampDispenserListener l = (StampDispenserListener) it.next(); 70 l.coinAccepted(event); 71 } 72 } 73 74 /** 75 * Helper method that fires stampDispensed events. 76 * 77 * @param event <code>StampDispenserEvent</code> to propagate 78 * @param listeners <code>Set</code> containing zero to many (and only) 79 * <code>StampDispenserListener</code>s 80 */ 81 static void fireStampDispensed(StampDispenserEvent event, 82 Set listeners) { 83 84 Iterator it = listeners.iterator(); 85 while (it.hasNext()) { 86 StampDispenserListener l = (StampDispenserListener) it.next(); 87 l.stampDispensed(event); 88 } 89 } 90 91 /** 92 * Helper method that fires coinsReturned events. 93 * 94 * @param event <code>StampDispenserEvent</code> to propagate 95 * @param listeners <code>Set</code> containing zero to many (and only) 96 * <code>StampDispenserListener</code>s 97 */ 98 static void fireCoinsReturned(StampDispenserEvent event, 99 Set listeners) { 100 101 Iterator it = listeners.iterator(); 102 while (it.hasNext()) { 103 StampDispenserListener l = (StampDispenserListener) it.next(); 104 l.coinsReturned(event); 105 } 106 } 107 } 1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 5 /** 6 * <code>State</code> subclass that represents the <em>Has0</em> stamp 7 * dispenser state. See the documentation for class <code>State</code> for a 8 * state transition table that specifies the required behavior of instances 9 * of this class. 10 * 11 * @author Bill Venners 12 */ 13 class Has0State extends State { 14 15 /** 16 * The single instance of <code>Has0State</code> 17 */ 18 private static Has0State singleton = new Has0State(); 19 20 /** 21 * Constructs a <code>Has0State</code> instance. This constructor is 22 * private to enable this class to restrict the number of instances of 23 * <code>Has0State</code> to one. I.e., <code>Has0State</code> is a 24 * singleton. 25 */ 26 private Has0State() { 27 } 28 29 /** 30 * Factory method that returns the single instance of 31 * <code>Has0State</code>. 32 */ 33 static State getState() { 34 return singleton; 35 } 36 37 /** 38 * Performs actions appropriate for the state represented by the class of 39 * this object for the add5 message. Returns a reference to the state 40 * object that represents the next state to transition to as a result of 41 * the arrival of this add5 message. 42 * 43 * @param stampDispenser the <code>StampDispenser</code> whose state this 44 * object represents 45 * @param listeners <code>Set</code> containing zero to many (and only) 46 * <code>StampDispenserListener</code>s 47 */ 48 State add5(StampDispenser stampDispenser, Set listeners) { 49 50 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 51 0, 5); 52 fireCoinAccepted(event, listeners); 53 return Has5State.getState(); 54 } 55 56 /** 57 * Performs actions appropriate for the state represented by the class of 58 * this object for the add10 message. Returns a reference to the state 59 * object that represents the next state to transition to as a result of 60 * the arrival of this add10 message. 61 * 62 * @param stampDispenser the <code>StampDispenser</code> whose state this 63 * object represents 64 * @param listeners <code>Set</code> containing zero to many (and only) 65 * <code>StampDispenserListener</code>s 66 */ 67 State add10(StampDispenser stampDispenser, Set listeners) { 68 69 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 70 0, 10); 71 fireCoinAccepted(event, listeners); 72 return Has10State.getState(); 73 } 74 75 /** 76 * Performs actions appropriate for the state represented by the class of 77 * this object for the returnCoins message. Returns a reference to the 78 * state object that represents the next state to transition to as a 79 * result of the arrival of this returnCoins message. 80 * 81 * @param stampDispenser the <code>StampDispenser</code> whose state this 82 * object represents 83 * @param listeners <code>Set</code> containing zero to many (and only) 84 * <code>StampDispenserListener</code>s 85 */ 86 State returnCoins(StampDispenser stampDispenser, Set listeners) { 87 return this; 88 } 89 } 1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 5 /** 6 * <code>State</code> subclass that represents the <em>Has5</em> stamp 7 * dispenser state. See the documentation for class <code>State</code> for a 8 * state transition table that specifies the required behavior of instances 9 * of this class. 10 * 11 * @author Bill Venners 12 */ 13 class Has5State extends State { 14 15 /** 16 * The single instance of <code>Has5State</code> 17 */ 18 private static Has5State singleton = new Has5State(); 19 20 /** 21 * Constructs a <code>Has5State</code> instance. This constructor is 22 * private to enable this class to restrict the number of instances of 23 * <code>Has5State</code> to one. I.e., <code>Has5State</code> is a 24 * singleton. 25 */ 26 private Has5State() { 27 } 28 29 /** 30 * Factory method that returns the single instance of 31 * <code>Has5State</code>. 32 */ 33 static State getState() { 34 return singleton; 35 } 36 37 /** 38 * Performs actions appropriate for the state represented by the class of 39 * this object for the add5 message. Returns a reference to the state 40 * object that represents the next state to transition to as a result of 41 * the arrival of this add5 message. 42 * 43 * @param stampDispenser the <code>StampDispenser</code> whose state this 44 * object represents 45 * @param listeners <code>Set</code> containing zero to many (and only) 46 * <code>StampDispenserListener</code>s 47 */ 48 State add5(StampDispenser stampDispenser, Set listeners) { 49 50 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 51 0, 10); 52 fireCoinAccepted(event, listeners); 53 return Has10State.getState(); 54 } 55 56 /** 57 * Performs actions appropriate for the state represented by the class of 58 * this object for the add10 message. Returns a reference to the state 59 * object that represents the next state to transition to as a result of 60 * the arrival of this add10 message. 61 * 62 * @param stampDispenser the <code>StampDispenser</code> whose state this 63 * object represents 64 * @param listeners <code>Set</code> containing zero to many (and only) 65 * <code>StampDispenserListener</code>s 66 */ 67 State add10(StampDispenser stampDispenser, Set listeners) { 68 69 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 70 0, 15); 71 fireCoinAccepted(event, listeners); 72 return Has15State.getState(); 73 } 74 75 /** 76 * Performs actions appropriate for the state represented by the class of 77 * this object for the returnCoins message. Returns a reference to the 78 * state object that represents the next state to transition to as a 79 * result of the arrival of this returnCoins message. 80 * 81 * @param stampDispenser the <code>StampDispenser</code> whose state this 82 * object represents 83 * @param listeners <code>Set</code> containing zero to many (and only) 84 * <code>StampDispenserListener</code>s 85 */ 86 State returnCoins(StampDispenser stampDispenser, Set listeners) { 87 88 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 89 5, 0); 90 fireCoinsReturned(event, listeners); 91 return Has0State.getState(); 92 } 93 } 1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 5 /** 6 * <code>State</code> subclass that represents the <em>Has10</em> stamp 7 * dispenser state. See the documentation for class <code>State</code> for a 8 * state transition table that specifies the required behavior of instances 9 * of this class. 10 * 11 * @author Bill Venners 12 */ 13 class Has10State extends State { 14 15 /** 16 * The single instance of <code>Has10State</code> 17 */ 18 private static Has10State singleton = new Has10State(); 19 20 /** 21 * Constructs a <code>Has10State</code> instance. This constructor is 22 * private to enable this class to restrict the number of instances of 23 * <code>Has10State</code> to one. I.e., <code>Has10State</code> is a 24 * singleton. 25 */ 26 private Has10State() { 27 } 28 29 /** 30 * Factory method that returns the single instance of 31 * <code>Has10State</code>. 32 */ 33 static State getState() { 34 return singleton; 35 } 36 37 /** 38 * Performs actions appropriate for the state represented by the class of 39 * this object for the add5 message. Returns a reference to the state 40 * object that represents the next state to transition to as a result of 41 * the arrival of this add5 message. 42 * 43 * @param stampDispenser the <code>StampDispenser</code> whose state this 44 * object represents 45 * @param listeners <code>Set</code> containing zero to many (and only) 46 * <code>StampDispenserListener</code>s 47 */ 48 State add5(StampDispenser stampDispenser, Set listeners) { 49 50 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 0, 15); 51 fireCoinAccepted(event, listeners); 52 return Has15State.getState(); 53 } 54 55 /** 56 * Performs actions appropriate for the state represented by the class of 57 * this object for the add10 message. Returns a reference to the state 58 * object that represents the next state to transition to as a result of 59 * the arrival of this add10 message. 60 * 61 * @param stampDispenser the <code>StampDispenser</code> whose state this 62 * object represents 63 * @param listeners <code>Set</code> containing zero to many (and only) 64 * <code>StampDispenserListener</code>s 65 */ 66 State add10(StampDispenser stampDispenser, Set listeners) { 67 68 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 69 0, 0); 70 fireStampDispensed(event, listeners); 71 return Has0State.getState(); 72 } 73 74 /** 75 * Performs actions appropriate for the state represented by the class of 76 * this object for the returnCoins message. Returns a reference to the 77 * state object that represents the next state to transition to as a 78 * result of the arrival of this returnCoins message. 79 * 80 * @param stampDispenser the <code>StampDispenser</code> whose state this 81 * object represents 82 * @param listeners <code>Set</code> containing zero to many (and only) 83 * <code>StampDispenserListener</code>s 84 */ 85 State returnCoins(StampDispenser stampDispenser, Set listeners) { 86 87 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 88 10, 0); 89 fireCoinsReturned(event, listeners); 90 return Has0State.getState(); 91 } 92 } 1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 5 /** 6 * <code>State</code> subclass that represents the <em>Has15</em> stamp 7 * dispenser state. See the documentation for class <code>State</code> for a 8 * state transition table that specifies the required behavior of instances 9 * of this class. 10 * 11 * @author Bill Venners 12 */ 13 class Has15State extends State { 14 15 /** 16 * The single instance of <code>Has15State</code> 17 */ 18 private static Has15State singleton = new Has15State(); 19 20 /** 21 * Constructs a <code>Has15State</code> instance. This constructor is 22 * private to enable this class to restrict the number of instances of 23 * <code>Has15State</code> to one. I.e., <code>Has15State</code> is a 24 * singleton. 25 */ 26 private Has15State() { 27 } 28 29 /** 30 * Factory method that returns the single instance of 31 * <code>Has15State</code>. 32 */ 33 static State getState() { 34 return singleton; 35 } 36 37 /** 38 * Performs actions appropriate for the state represented by the class of 39 * this object for the add5 message. Returns a reference to the state 40 * object that represents the next state to transition to as a result of 41 * the arrival of this add5 message. 42 * 43 * @param stampDispenser the <code>StampDispenser</code> whose state this 44 * object represents 45 * @param listeners <code>Set</code> containing zero to many (and only) 46 * <code>StampDispenserListener</code>s 47 */ 48 State add5(StampDispenser stampDispenser, Set listeners) { 49 50 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 51 0, 0); 52 fireStampDispensed(event, listeners); 53 return Has0State.getState(); 54 } 55 56 /** 57 * Performs actions appropriate for the state represented by the class of 58 * this object for the add10 message. Returns a reference to the state 59 * object that represents the next state to transition to as a result of 60 * the arrival of this add10 message. 61 * 62 * @param stampDispenser the <code>StampDispenser</code> whose state this 63 * object represents 64 * @param listeners <code>Set</code> containing zero to many (and only) 65 * <code>StampDispenserListener</code>s 66 */ 67 State add10(StampDispenser stampDispenser, Set listeners) { 68 69 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 70 5, 0); 71 fireStampDispensed(event, listeners); 72 return Has0State.getState(); 73 } 74 75 /** 76 * Performs actions appropriate for the state represented by the class of 77 * this object for the returnCoins message. Returns a reference to the 78 * state object that represents the next state to transition to as a 79 * result of the arrival of this returnCoins message. 80 * 81 * @param stampDispenser the <code>StampDispenser</code> whose state this 82 * object represents 83 * @param listeners <code>Set</code> containing zero to many (and only) 84 * <code>StampDispenserListener</code>s 85 */ 86 State returnCoins(StampDispenser stampDispenser, Set listeners) { 87 88 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 89 15, 0); 90 fireCoinsReturned(event, listeners); 91 return Has0State.getState(); 92 } 93 }
StampDispenser
Has0State
has no state
1 package com.artima.examples.stampdispenser.ex3; 2 3 import java.util.Set; 4 5 /** 6 * <code>State</code> subclass that represents the <em>Has0</em> stamp 7 * dispenser state. See the documentation for class <code>State</code> for a 8 * state transition table that specifies the required behavior of instances 9 * of this class. 10 * 11 * @author Bill Venners 12 */ 13 class Has0State extends State { 14 15 /** 16 * The single instance of <code>Has0State</code> 17 */ 18 private static Has0State singleton = new Has0State(); 19 20 /** 21 * Constructs a <code>Has0State</code> instance. This constructor is 22 * private to enable this class to restrict the number of instances of 23 * <code>Has0State</code> to one. I.e., <code>Has0State</code> is a 24 * singleton. 25 */ 26 private Has0State() { 27 } 28 29 /** 30 * Factory method that returns the single instance of 31 * <code>Has0State</code>. 32 */ 33 static State getState() { 34 return singleton; 35 } 36 37 /** 38 * Performs actions appropriate for the state represented by the class of 39 * this object for the add5 message. Returns a reference to the state 40 * object that represents the next state to transition to as a result of 41 * the arrival of this add5 message. 42 * 43 * @param stampDispenser the <code>StampDispenser</code> whose state this 44 * object represents 45 * @param listeners <code>Set</code> containing zero to many (and only) 46 * <code>StampDispenserListener</code>s 47 */ 48 State add5(StampDispenser stampDispenser, Set listeners) { 49 50 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 51 0, 5); 52 fireCoinAccepted(event, listeners); 53 return Has5State.getState(); 54 } 55 56 /** 57 * Performs actions appropriate for the state represented by the class of 58 * this object for the add10 message. Returns a reference to the state 59 * object that represents the next state to transition to as a result of 60 * the arrival of this add10 message. 61 * 62 * @param stampDispenser the <code>StampDispenser</code> whose state this 63 * object represents 64 * @param listeners <code>Set</code> containing zero to many (and only) 65 * <code>StampDispenserListener</code>s 66 */ 67 State add10(StampDispenser stampDispenser, Set listeners) { 68 69 StampDispenserEvent event = new StampDispenserEvent(stampDispenser, 70 0, 10); 71 fireCoinAccepted(event, listeners); 72 return Has10State.getState(); 73 } 74 75 /** 76 * Performs actions appropriate for the state represented by the class of 77 * this object for the returnCoins message. Returns a reference to the 78 * state object that represents the next state to transition to as a 79 * result of the arrival of this returnCoins message. 80 * 81 * @param stampDispenser the <code>StampDispenser</code> whose state this 82 * object represents 83 * @param listeners <code>Set</code> containing zero to many (and only) 84 * <code>StampDispenserListener</code>s 85 */ 86 State returnCoins(StampDispenser stampDispenser, Set listeners) { 87 return this; 88 } 89 }
ComplexNumber
Object1 package com.artima.examples.complexnum.ex1; 2 3 /** 4 * Represents a complex number whose real and imaginary components are 5 * <CODE>double</CODE>s. 6 * 7 * @author Bill Venners 8 */ 9 public class ComplexNumber { 10 11 private double real; 12 private double imaginary; 13 14 /** 15 * Construct a new <code>ComplexNumber</code> with the passed real and 16 * imaginary components. 17 * 18 * @param real the real component of this <code>ComplexNumber</code> 19 * @param imaginary the imaginary component of this 20 * <code>ComplexNumber</code> 21 */ 22 public ComplexNumber(double real, double imaginary) { 23 24 this.real = real; 25 this.imaginary = imaginary; 26 } 27 28 /** 29 * Returns the real component of this <code>ComplexNumber</code>. 30 * 31 * @return the real component of this <code>ComplexNumber</code> 32 */ 33 public double getReal() { 34 return real; 35 } 36 37 /** 38 * Returns the imaginary component of this <code>ComplexNumber</code>. 39 * 40 * @return the imaginary component of this <code>ComplexNumber</code> 41 */ 42 public double getImaginary() { 43 return real; 44 } 45 46 /** 47 * Returns the conjugate of this complex number. The conjugate of complex 48 * number a + <em>i</em>b is a - <em>i</em>b. 49 * 50 * @return the conjugate of this <code>ComplexNumber</code> 51 */ 52 public ComplexNumber getConjugate() { 53 54 return new ComplexNumber(real, -imaginary); 55 } 56 57 /** 58 * Compares the passed <CODE>ComplexNumber</CODE> to this 59 * <code>ComplexNumber</code> for equality. Two 60 * <code>ComplexNumber</code> objects are semantically equal if their 61 * real components are equal and their imaginary components are equal. 62 * 63 * @param An object to compare to this <code>ComplexNumber</code> 64 * @return <code>true</code> if this <code>ComplexNumber</code> is 65 * semantically equal to the passed <code>ComplexNumber</code> 66 */ 67 public boolean equals(Object o) { 68 69 if ((o == null) || (getClass() != o.getClass())) { 70 return false; 71 } 72 73 // This can't fail because the class of o is exactly ComplexNumber, 74 // as was proven when (getClass() != o.getClass()) returned false 75 ComplexNumber cn = (ComplexNumber) o; 76 77 // Because this class extends Object, don't call super.equals() 78 79 // To be semantically equal, the complex numbers must have equal 80 // real and imaginary components 81 if ((real != cn.real) || (imaginary != cn.imaginary)) { 82 return false; 83 } 84 85 return true; 86 } 87 88 /** 89 * Computes the hash code for this <code>ComplexNumber</code>. 90 * 91 * @return a hashcode value for this <code>ComplexNumber</code> 92 */ 93 public int hashcode() { 94 95 // Got this idea from Double's hashcode method. 96 long re = Double.doubleToLongBits(real); 97 long im = Double.doubleToLongBits(imaginary); 98 99 int rex = (int) (re ^ (re >>> 32)); 100 int imx = (int) (im ^ (im >>> 32)); 101 102 return rex ^ imx; 103 } 104 105 /** 106 * Adds the passed <code>ComplexNumber</code> to this one. The sum of two 107 * complex numbers a + <em>i</em>b and c + <em>i</em>d is (a + c) + 108 * <em>i</em>(c + d). 109 * 110 * @param addend the <code>ComplexNumber</code> to add to this one 111 * @returns the sum of this and the passed <code>ComplexNumber</code> 112 */ 113 public ComplexNumber add(ComplexNumber addend) { 114 115 return new ComplexNumber(real + addend.real, 116 imaginary + addend.imaginary); 117 } 118 119 /** 120 * Subtracts the passed <code>ComplexNumber</code> from this one. The 121 * difference between two complex numbers, a + <em>i</em>b - c + 122 * <em>i</em>d, is (a - c) + <em>i</em>(b - d). 123 * 124 * @param subtrahend the <code>ComplexNumber</code> to subtract from this 125 * <code>ComplexNumber</code> 126 * @return the difference of this and the passed 127 * <code>ComplexNumber</code>s 128 */ 129 public ComplexNumber subtract(ComplexNumber subtrahend) { 130 131 return new ComplexNumber(real - subtrahend.real, 132 imaginary - subtrahend.imaginary); 133 } 134 135 /** 136 * Multiplies this <code>ComplexNumber</code> (the multiplicand) with the 137 * passed <code>ComplexNumber</code> (multiplier). The product of two 138 * complex numbers a + <em>i</em>b and c + <em>i</em>d is (ac - bd) + 139 * <em>i</em>(bc + ad). 140 * 141 * @param multiplier the <code>ComplexNumber</code> with which to 142 * multiply this <code>ComplexNumber</code> 143 * @return the product of this and the passed 144 * <code>ComplexNumber</code> 145 */ 146 public ComplexNumber multiply(ComplexNumber multiplier) { 147 148 double prodReal = (real * multiplier.real) 149 - (imaginary * multiplier.imaginary); 150 double prodImaginary = (imaginary * multiplier.real) 151 + (real * multiplier.imaginary); 152 153 return new ComplexNumber(prodReal, prodImaginary); 154 } 155 156 /** 157 * Divides this <code>ComplexNumber</code> (the numerator) by the passed 158 * <code>ComplexNumber</code> (denominator). The quotient of two complex 159 * numbers a + <em>i</em>b / c + <em>i</em>d is ((ac + bd) + 160 * <em>i</em>(bc - ad)) / (c*c + d*d). 161 * 162 * @param denominator the <code>ComplexNumber</code> by which to divide 163 * this <code>ComplexNumber</code> 164 * @return the quotient of this divided by the passed 165 * <code>ComplexNumber</code>s 166 */ 167 public ComplexNumber divide(ComplexNumber denominator) { 168 169 // Perform division by first multiplying both the numerator and 170 // denominator by the conjugate of the denominator. 171 ComplexNumber conj = denominator.getConjugate(); 172 ComplexNumber tempNumerator = multiply(conj); 173 ComplexNumber tempDenominator = denominator.multiply(conj); 174 175 // By multiplying the denominator by its conjugate, its imaginary 176 // component drops to zero. Can then just divide the real and 177 // imaginary components of the numerator by the denominator's real 178 // value. 179 return new ComplexNumber(tempNumerator.real / tempDenominator.real, 180 tempNumerator.imaginary / tempDenominator.real); 181 } 182 }
int
, float
, ...
ComplexNumber
, a Matrix
,
or a Bitmap
?