Software Development I – Exercises Winter Term 2012/2013 Übungen zu Softwareentwicklung 1

2013-01-08
A. Riener/Institute for Pervasive Computing
Software Development I – Exercises
Winter Term 2012/2013
Übungen zu Softwareentwicklung 1
Assignment 6
Name: ___________________________________
Teaching Assistant: ___________________
Student ID (Matr.Nr.): ______________________
Points (max. 24): _____________________
Group: ___________________________________
Deadline:
Instructor: ________________________________
Editing time: ________________________
Question 1: Smartphone Shop
Wed, Dec. 5th‚ 2012 12:00 noon
8 points
Given a fictitious shop (class Shop) selling smartphones, write a program that can manage
heterogeneous devices with different technical features. Each phone (class Phone) has a name, a
“unique” product number, and five more specifications (CPU, storage, resolution, OS, weight). All
the attributes should be stored as strings (data type String).
The class Phone should provide a constructor with the phone’s name as parameter (data type
String). Furthermore, you are requested to initialize the product number with a 10-digit(!)
random integer number (you can start with Math.random() to get a pseudo random number in
the interval [0;1[).
The class Shop stores the phones in an array of phones (Phone[]) of an arbitrary but explicitly
set length (use a constant for creating the array – see the example below). Test your program by
filling your array with a number of phones (at least 3) and printing them to the screen. Your console
output should look similar to this:
Phone 1: Apple iPhone 5 [#2716346936] -­‐CPU: 1.3 GHz dual core Apple A6 -­‐OS: iOS 6.0.1 -­‐Resolution: 640x1136 -­‐Storage: 64 GB -­‐Weight: 112 g Phone 2: Samsung Galaxy S III [#3087884400] -­‐CPU: 1.4 GHz quad-­‐core Cortex-­‐A9 -­‐OS: Android 4.0 (Ice Cream Sandwich) -­‐Resolution: 720x1280 -­‐Storage: 32 GB -­‐Weight: 133 g
Use setter methods to set the phone’s features and getter methods for the output. Have a look at the
following Java code snippet to get an idea how to solve this exercise.
// Initialize the shop Shop shop = new Shop(); // Initialize the array as container for numerous smartphones. // Use a constant for the array length Phone[] phones = new Phone[MAX_NUM_PHONES]; // Create a new phone and set its features and attributes Phone apple = newPhone("Apple iPhone 5"); apple.setCpu("1.3 GHz dual core Apple A6"); // ... // Add the phone to the shop’s phone array phones[0] = apple; // Add and print the phones to the screen shop.addPhones(); shop.printPhones(); - Page 1/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Test your program by creating and adding some phones in a private method addPhones() which
you can call in the main method of the class Shop (see example above). You do not need to
implement a user dialog, just fill the array by using the constructor and the setter methods of the
class Phone (as can be seen in the code example above). Provide the source code for all
implemented classes.
Write the program in Java. Provide all the material requested below at the very bottom
(“Requested material…”)
Question 2: Interactive Electronic Shop
16 points
Extend the basic functionality of your code from question 1 to give the user a more interactive
experience when visiting your shop. Furthermore, your shop can now manage arbitrary electronic
devices (e.g., smartphones, laptops, tablets, MP3 player, etc.) which are implemented as products
(class Product).
Class Product: Besides the mandatory fields (name, price, 10-digit product number), a product
can have a maximum number of 10 optional features (class Feature) which are stored in a feature
array (Feature[]). A feature consists of a name and a description both implemented as strings.
Class Shop: The electronic shop has a name and an array of products (Product[]) to store a
maximum number of 100 devices (use a constant to initialize the array).
To make the implementation a bit easier for you, stick to the given interface and implement at least
the following methods (in addition to the general getter and setter methods that you will need):
Shop:
// The constructor public Shop(String name) {...} // Method to add a product p to the shop public boolean addProduct(Product p) {...} // Method to remove a product at a certain index public boolean removeProduct(int index) {...} // Get a product at a certain index public Product getProduct(int index) {...} // Returns a string representation of all the products public String printProducts() {...}
Product:
// The constructor public Product(String name, double price) {...} // Method to add a feature f to the product public boolean addFeature(Feature f) {...} // Method to remove a feature at a certain index public boolean removeFeature(int index) {...} // Returns a string representation of all the features public String printFeatures() {...}
Implement a simple interactive dialog on the console where the user can always pick one option by
entering a single number. The following examples show, how the user interaction could look like:
- Page 2/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Printing the product list:
========================================
My TestShop
========================================
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
1
[0] PC (#9828286677)
[1] Phone (#6633696897)
[2] Tablet (#9743925129)
[3] MP3-Player (#9844343263)
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
Adding a product to the shop:
========================================
My TestShop
========================================
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
2
Please enter the product's name: NewName
Please enter the product's price: 99.99
Please enter a feature (name=description)
Please enter a feature (name=description)
Please enter a feature (name=description)
Invalid input. Please try again.
Please enter a feature (name=description)
Please enter a feature (name=description)
or hit enter to return: Name1=Desc1
or hit enter to return: Name2=Desc2
or hit enter to return: Name3
or hit enter to return: Name3=Desc3
or hit enter to return:
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
1
[0] PC (#7743008378)
[1] Phone (#8172776236)
[2] Tablet (#4805652465)
[3] MP3-Player (#7847288797)
[4] NewName (#3320841722)
Deleting a product from the shop:
========================================
My TestShop
========================================
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
3
[0] PC (#3917852306)
[1] Phone (#2278893349)
[2] Tablet (#2137225131)
[3] MP3-Player (#1316591533)
Please select the index of the product to delete: 2
Product removed successfully!
- Page 3/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
1
[0] PC (#3917852306)
[1] Phone (#2278893349)
[2] MP3-Player (#1316591533)
Changing the name of a product:
========================================
My TestShop
========================================
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
4
[0] PC (#2645449902)
[1] Phone (#8915678527)
[2] Tablet (#4192119749)
[3] MP3-Player (#9466447194)
Please select the index of the product:
2
Product Tablet (#4192119749) selected: [Price=549.0], [Brand=ASUS], [USB Ports=1],
[Resolution=1280x800 pixels], [Weight=635 g]
Please select option:
[1] Change product name
[2] Change product price
[3] Change product features
[4] Return
1
Current name is: "Tablet"
Enter new name: TabletNew
Product name changed successfully!
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
1
[0] PC (#2645449902)
[1] Phone (#8915678527)
[2] TabletNew (#4192119749)
[3] MP3-Player (#9466447194)
Modifying the features of a product:
========================================
My TestShop
========================================
Please select option:
[1] Print product list
[2] Add product
[3] Delete product
[4] Show product details
[5] Exit program
4
[0] PC (#6863665806)
[1] Phone (#5761482749)
[2] Tablet (#4618101920)
[3] MP3-Player (#7138583416)
Please select the index of the product:
2
Product Tablet (#4618101920) selected: [Price=549.0], [Brand=ASUS], [USB Ports=1],
[Resolution=1280x800 pixels], [Weight=635 g]
- Page 4/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Please select option:
[1] Change product name
[2] Change product price
[3] Change product features
[4] Return
3
The selected product has the following features:
[0] [Brand=ASUS]
[1] [USB Ports=1]
[2] [Resolution=1280x800 pixels]
[3] [Weight=635 g]
Please select one option:
[1] Delete an existing feature
[2] Add a new feature
[3] Return
1
[0] [Brand=ASUS]
[1] [USB Ports=1]
[2] [Resolution=1280x800 pixels]
[3] [Weight=635 g]
Please enter the index of the feature to be deleted: 3
Feature successfully removed.
Please select one option:
[1] Delete an existing feature
[2] Add a new feature
[3] Return
1
[0] [Brand=ASUS]
[1] [USB Ports=1]
[2] [Resolution=1280x800 pixels]
Hints:
§ Splitting the user dialog into several methods (e.g., printAddProductDialog(),
printDeleteProductDialog(), printProductDetailsDialog(), etc.) might
be useful.
§ Use the method String[] java.lang.String.split(String regex)to split
the feature entered by the user into the fields 'name' and 'description'.
Write the program in Java. Provide all the material requested below at the very bottom
(“Requested material…”)
Requested material for all programming problems:
§ For each exercise, hand in the following:
a) The idea for your solution written in text form.
b) Source code (Java classes including English(!) comments).
c) Test plan for analyzing boundary values (e.g., min. temperature allowed, maximum
number of input, etc.) and exceptional cases (e.g., textual input when a number is
required). State the expected behavior of the program for each input and make sure
there is no “undefined” behavior leading to runtime exceptions. List all your test
cases in a table (test case #, description, user input, expected (return) values).
d) The output of your java program for all test cases in your test plan.
§
Pay attention to using adequate and reasonable data types for your implementation, check the
user input carefully and print out meaningful error messages.
Advice for user input: While no longer mandatory it is still recommended to use the class
Input.java for user input (read operations) in your program.
- Page 5/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
OOP Tutorial and Hints for the Sample Solution
a) Some words about object oriented programming
In the first part we will discuss object orientated programming. This should help those students
which “think” to know but are not 100% sure.
An object is exactly what the name “object” means. It’s a thing, a device or an abstract idea which
you want to model.
For example, a book is an arbitrary object with the ability “give us information”. So when we want
to implement this book (for a library program or something like that) we would need a class. A
class is the “idea” of the object, or the template how to build it. So if we have the idea how to build
a book will are able to build one. After you built one you we have an object from the idea “book”
with a specific ability.
In OOP it behaves in the same way. We implement classes (idea/template/guidelines), with them we
instantiate objects (the real thing) from that class. This object has several methods (abilities) which
we can use.
Methods are abilities, which the object has. For example “retrieveInformation()” could be a method
of a book object. But as you see, this function shouldn’t be a static one because than it would apply
on all objects of this class in the same manner. You would get from each book the same information
which would be really useful.
Constants, using the same metaphor, would be something which holds for all objects of this class
(for each thing of the idea). Take for example the Boolean constant
“CONTAINS_INFORMATION”. Every book contains information so we would set this constant to
true. This constant should hold for all books we make, or it wouldn’t be a reasonable constant.
Fields would be object specific properties like “amountOfPages”. This field can differ in each book
object, but that’s ok.
Off course the more abstract you get with you modelling the more exception you get from those
commonalities between real world and OOP, but this explanation should help you to understand
how things work together and how they are connected.
Frequently made mistakes (general + OOP)
Conditions
Examples
if (someBoolean == true) {
// lots of code
}
while (someBoolean == false) {
// lots of code
}
if (someBoolean ) {
// lots of code
}
while (!someBoolean) {
// lots of code
}
There is no need to check a Boolean against another Boolean within a condition. If someBoolean is
true, the check against true won’t change anything. If the loop should stop when someBoolean is
false, it suffices to say: stop if we not have someBoolean.
This is not a real mistake but since the additional operand complicates the expression we will stick
to the shorter version.
Examples Do not use unnecessary complex expression as there is no benefit using them…
• They are hard to read
• They are hard to understand
- Page 6/23 -
2013-01-08
•
•
A. Riener/Institute for Pervasive Computing
They cost time (which somebody needs to pay)
They are hard to debug
for (int i = 0, j = 1; i < array.length; i += j % 2 == 0 ? 1 : 2 * i)
{
// lots of code
}
Break, Continue
int i = 0;
while (i < array.length) {
// lots of code
if (i % 2 == 0) {
// some code
continue;
}
// lots of code
if (i + 2 == 3) {
break;
}
// lots of code
i++;
}
Example
Try to avoid continue and break. They are just disguised
goto’s which destroy the sequential structure of the code.
They also make your code prone for bugs. In this example
the increment will be skipped and we probably end up in an
endless loop. Using break in a big loop, or a return in the
middle of a function is usually equalled dangerous if you
don’t know what you are doing.
There are many articles about continue and break and why
they should not be used, read them.
Naming
Example
public class vending_machine {
private static final int foo_bar;
public void Searching(int Parameter_one) {
int i, j, k;
while (i < k) {
// lots of code
}
}
}
Naming conventions are very important, not just to get all of the code from different people in one
form but also it helps to make code more readable and thus faster to work with.
Classes are capital camel, so they start always with a capital letter.
Methods and variables are always in lower case so they start with a lower letter. Constants are
always capitalized and the separate symbol is the underscore.
- Page 7/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
public class VendingMachine {
private static final int FOO_BAR = 1;
public void searchingForVariable(int variable) {
int rowIndex = 0, columnIndex = 0, arrayIndex;
while (rowIndex < columnIndex) {
// lots of code
}
}
}
Always use names which tell a story. At its best you shouldn’t even need to comment your code
because the names of the used variables, methods, and classes tell you everything you need to
know.
Use names which fit to the purpose. A function called, binarySearch should implement a
binarySearch algorithm and nothing else. People who use your classes and function rely on your
names and on your documentation.
Objects
Objects model a specific “thing” of the real world (or an abstract one) so that we are able to build
complex program structures with them. In this example we have the Shop class from which we can
instantiate Shop objects. Somehow the coder decided to put some program control code into the
class, the printMenu function. I don’t know any shop in the real world which ask me to choose a
product (shop assistants do that), so why should I implement it in a program. Packing functionality
into classes which shouldn’t have them is not a good idea because they complicate the use of the
classes and makes them prone to redundant code. The interaction with the user should stay in a
separate class which acts as a control class (Main class) or only handles user inputs.
Example
public class Shop {
// Getters and Setter for fields...
// Lots of code
public void printMenu() {
int selection;
System.out.println("Choose a product: ");
selection = Input.readInt();
// some more inputs
System.out.println("Printing Product specs...");
}
}
Constructing Objects
There are several ways to construct and initialize an object, but all involve somehow the new key
word (expect of reflection). Using a pattern like the above one is problematic. It not only uses the
standard constructor to instantiate an object of this class (which is always available if none other
constructor is there) but also a specific method. The method must be static (or you cannot call it
within a different object) and the coder intended to get a field filled with data (because it’s a
mandatory field in this class and never should be empty or null). The big problem with this code is
that other users can still call the standard constructor an instantiate objects without the mandatory
initializations.
- Page 8/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Example
public class Product {
private String productName;
public static Product newProduct(String productName) {
Product product = new Product();
product.productName = productName;
return product;
}
}
public class Main {
public static void main(String[] args) {
Product product = Product.newProduct("Foo");
Product product1 = new Product();
}
}
The following pattern uses a private constructor and a static create method to instantiate the object.
Now nobody can create an object through a different constructor because there are none and the
standard constructor is private (only the object itself can use it). This makes sense if you built up a
framework or use a specific pattern. This is the standard pattern how to use the standard constructor
and the new operator to construct a product object. This is definitely the way how you want to
construct objects in this course.
public class Product {
private String productName;
private Product() {
// Do some initializations
}
public static Product createProduct(String productName) {
return new Product();
}
}
public class Main {
public static void main(String[] args) {
Product product = Product.createProduct("Foo");
}
}
- Page 9/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
public class Product {
private String productName;
public Product(String productName) {
this.productName = productName;
}
}
public class Main {
public static void main(String[] args) {
Product product = new Product("Foo");
}
}
Methods
Example
This is a good example how to not develop your methods. Public methods provide the object with
class specific functionalities or if they are private they are used to split up specific areas of the code
which later can be reused again. So a method does exactly one thing- it has one purpose.
This example method retrieves the input from the user, calculates somehow a result and prints it. If
we want to calculate the same result within a different context we are forced to duplicate our code.
If we want to design several different ways how to print the result we would get problem with this
implementation.
private void getUserInput() {
// small nice method
}
private int calculate() {
// small nice method
return 0;
}
private void print() {
// small nice method
}
Split up things to get a better usability of them and to structure your code correctly. The rule of
thumb says: if your method is bigger than the half of your monitor size it’s certain that you need to
split things up. Use this “rule” to code; it serves for most situations (except you code a Swing GUI
or other declarative stuff).
Visibility
To assign the correct visibility in a specific context is very important. For instance you don’t want
that anybody is able to modify your productNumber or name field. Somebody could assign null to
the string and all of your code which relies on a none-null-value will probably crash.
Or think of user sensitive data. If the visibility is not correct, somebody could read them out and use
them.
The next problem with this example is that the constructor is not public (except you want it like
that) which will prevent other objects, outside this package, to instantiate this object.
Fields should never be directly accessible except you have an util class like Point for example.
Constants can be public because they are immutable, but you still need to consider the sensitivity of
the information you are about to make public.
- Page 10/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Example
public class Product {
String name;
long productNumber;
Product() {
/* do init */ }
private void getUserInput() { /* lots of code */ }
public void calculate() { /* lots of code */ }
void getName() { /* lots of code */ }
}
If you don’t know if a method should be private or public just make it private and look if the
compiler complains (because he cannot find the method). If not, it’s a hint (but nothing more) that
this method should be private, you still need to think about your decision.
public class Product {
public static final String SOME_CONSTANT = "foo";
private String name;
private long productNumber;
public Product() {
/* do init */ }
private void getUserInput() { /* lots of code */ }
private void calculate() { /* lots of code */ }
public void getName() { /* lots of code */ }
...
}
Immutable
Example
public class Product {
public static final int MAX_FEATURE_AMOUNT = 10;
private Feature[] features;
private int id;
public Product() {
features = new Feature[MAX_FEATURE_AMOUNT];
}
private void workWithFeatures(Feature[] features) {
// lots of code on the feature array
}
}
In this example we will discuss which values should be editable and which not. This example shows
you a product class. Each product has a fixed amount of features. So as we can see
MAX_FEATURE_AMOUNT will be a constant.
- Page 11/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
If we do not assign a new features array within the class the features array should be an immutable.
Furthermore the class has an id. Ids normally don’t change because they should identify the object
in a superior way (no other product should have the same id). Therefore this field should also be an
immutable field.
It is good practice in function signatures to assign the final keyword to the values. It shows that you
don’t mess with the objects you use. Furthermore if the compiler complaints because you set the
parameters to final, I strongly recommend to revise your method because it’s likely that you made a
mistake.
public class Product {
public static final int MAX_FEATURE_AMOUNT = 10;
private final Feature[] features;
private final int id;
public Product() {
features = new Feature[MAX_FEATURE_AMOUNT];
id = 1; // just a example
}
private void workWithFeatures(final Feature[] features) {
// lots of code on the feature array
}
}
Constants
Example
public class Product {
public static final int A_CONSTANT = 10;
private final Feature[] features;
private static int id;
private final int foo;
}
The difference between a constant and an immutable field is that the constant belongs to the class.
In this case id wouldn’t be a constant because it’s not immutable. Nevertheless it belongs to the
class.
Foo is not constant. It’s immutable but belongs to an object from the product class. A constant is a
value which accounts for all of the objects from a class. For example the Boolean: hasAHeart
should definitely be a constant in a class called human. So we would write [public|private] static
final HAS_A_HEART to make the Boolean a constant. Now the assign value accounts for all
objects of this class and is for all objects true.
Example
Object[ ] array = new Object[100];
for (int i = 0; i < 100; i++) {
// lots of code
}
You should never use any magic constants. They are called like that because nobody knows where
they come from. As you see you need to look twice at the code to understand where it comes from.
First recognizing the constant; secondly looking for a link between the rest of the code and the
constant.
- Page 12/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
You definitely want to avoid them unless it is obvious what you are trying to do and you don’t have
any other possibility. As for the exercise 6, you can further improve the code (menu section) by
using enums for the menu item numbering, instead of magic constants.
Object[] array = new Object[100];
for (int i = 0; i < array.length; i++) {
// lots of code
}
Random Numbers
Example
long digit10 = (long) (Math.random() * 1000000000);
If you try to get a random 10 digit number, you need to keep in mind, that the random method
returns a value between [0,1[. Multiplying the value with the maximum of your range creates a
random number between 0 and the maximum range (exclusive). But 0 has not 10 digits (except you
make 10 zero out of it).
Standard Patterns
Range
[0,1[
[0, max[
[min, max[
[min, max]
Method call
Math.random()
Math.random() * max
Min + Math.random()*(max – min)
Min + Math.random()*((max-min)+1)
Setters & Getters
Example
public class Rectangle {
private int width;
private int height;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
The main reason why we make the fields private is that we do not want somebody to write an
invalid state into it. For example the field name should not point to null because it increases the
probability for a null pointer exception (when working with the name).
So we implement methods, setters and getters, which control the access to a field.
The example on the left side shows a Rectangle class which provides getters and setters for the
fields.
- Page 13/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
The code is perfectly valid for the compiler, but as it is, it would make no big deference if we would
make the width and height public. There is no checking so every value can be assign.
public class Rectangle {
private int width;
private int height;
public void setWidth(int width) {
if (width >= 0) {
this.width = width;
}
}
public void setHeight(int height) {
if (height >= 0) {
this.height = height;
}
}
}
Because width and height are length values, it wouldn’t make sense to assign negative value to
them. To avoid an illegal state of the object, we check in the setters the value someone wants to
assign on the fields and therefore make sure that the object stays in a valid state.
You should always code in a defensive way because it makes you programs more solid.
An extension to this example would be to return a Boolean if the set operation was successful or
not, so the caller can act in an appropriate way if something went wrong.
Keyword: Static
The next part will (hopefully) bring light onto the use of the keyword ‘static’ because at the beginning of OOP students
tend to misunderstand/misuse it…
Static on Fields
If you use the keyword static, you always refer to the class and not to the object. For instance if you
have an object with the field “name” and you use the static keyword on it, the object field “name”
becomes a class field “name”. The result is that every object of this class will have the same name.
In most cases that is definitely not what you want.
So be sure where to put your static and where not.
At the beginning it is not always clear what static keyword does, because you mix up classes and
their objects.
public class Rectangle {
private static int width;
private int height;
public void setWidth(int width) {
if (width > 0) {
Rectangle.width = width;
}
}
public void setHeight(int height) {
if (height > 0) {
this.height = height;
}
}
}
- Page 14/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
If we have a class field, we can access it through an object of the class (because every object was
made from this class) but usually you access the field trough the class itself.
This example shows you the class field width, and the object field height. If you want to implement
Tetris for instance you could use a rectangle to build up the shapes of the blocks. If you now assign
a value on width through the setter, every single shape would change because the width refers to the
class and not to a single object (it would be the same as if you would say: “every human being is
1.8 meters tall). Despite that every rectangle object could have its own height.
Static on Methods
In every java program there is at least one static method – the main method. This method serves as
entrance point. Without such an entrance point the compiler would not know where to start the
program.
As for the variables, static methods belong to the class and not to the object. So they are called by
the class and not by the object. That’s the reason why the main method must be static. The compiler
looks for all static methods (because he can interact with them without haven an object) and
searches the one which is called “main” (which is by convention the entrance point of your
program). If the program starts to run the call SomeClassWithMainMethod.main(params) happens
and now your code is executed.
public class Main {
private int foo = 14;
private int bar = 7;
public static void main(String[] args) {
foo += bar;
}
}
Within a static method, it is not possible to access the object fields. The static method works in the
class and not in your object, so how should it be possible?
The naïve solution is to set the fields also static so that you can access them through the static
method.
public class Main {
private
private
final int foo = 14;
final int bar = 7;
public static void main(String[] args) {
Main object =new Main();
object.foo += object.bar;
}
}
public class Main {
private static final int foo = 14;
private static final int bar = 7;
public static void main(String[] args) {
foo += bar;
}
}
But as we already discussed in the previous section this will make foo and bar to class fields. So we
cannot instantiate multiple objects of this class with different foo and bar values. This is
unsatisfying (think of the Tetris example).
- Page 15/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
If you want to work with object fields in a static method you will need an object of this class. If you
don’t have one, create one.
At the first glance is looks odd to create a new main object in the main class and work with the
fields (because the names are the same). But it’s the same like working in an arbitrary object with
the main object - Nothing more.
Program Structure
A good structured program is maintainable, fast in execution and extensible. Therefore we need to
abstract a big problem into various smaller problems. Think of exercise 6 (Interactive Electronic
Shop) where a shop has an arbitrary number of products, and the products have an arbitrary number
of features and so on. A good structure will break up the problem into: Shop, Products, Features and
Costumer interaction (Main class).
Now we try to abstract those pieces.
§ Features: We make a Feature class with the name and the description
§ Product: We make a Product class with the name and an Feature array to hold the product
features
§ Shop: We make a Shop class with the name and a Product array to hold the products.
§ Main: We construct a shop, add some products (w/ features) and start the conversation with
the user.
As we see a good program structure allows us to have many products with many features and if we
want we can extends the shop with services without disturbing the flow of shop, product and
features.
Each class is good maintainable because it models one single object.
When implement the methods for the classes, we always keep in mind that functions are abilities
the objects have. For instance it wouldn’t make sense to give the Feature class a method
printFeatures(). Features are just facts and don’t have an ability to print something.
It would make sense to make a method getFeature() which returns a string with the name and the
description. The problem with this method is that the format of (name, description) is fixed. So if
many coders use your class it’s likely that they want a different format and they would get (name,
description) separately from the getters.
So always keep in mind which functions you implement and how you and other coders can use
them.
Guideline: Code short and simple, because then it’s fast and understandable.
Exceptions
boolean invalidInput = true;
while (invalidInput) {
try {
int selection = Input.readInt();
if (selection < 0 || selection > 5) {
throw new IndexOutOfBoundsException();
} else {
invalidInput = false;
}
} catch (IndexOutOfBoundsException e) {
System.out.println("Error: Invald input");
}
}
- Page 16/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
We use exceptions to signal that an error occurred. A runtime exception is system errors; a user
exception is “coder” error.
This example shows a misuse of exception. Exception should signal that something is wrong with
the code. In this case the exception signals that the user entered a wrong selection.
You don’t want to use exceptions for trivial stuff, and anyway, a wrong user input is no error at all.
Think of linux shell scripting. At the beginning the probability that you enter something wrong is
way higher than entering something correct. So we could say wrong user inputs are more “normal”
than the correct once (for beginners).
Code Structure / Code Format
Most of the times the code you will write will be read a long time after you have written it. So it is
important to comment it but also keep to keep your code in a good shape.
If you encounter a problem and you implement it, it is likely that the code will get a certain shape
within a certain class of problems.
For instance take the user interface from exercise 6. We have a main menu, a product menu and a
change product menu. Implementing all menus in one function will give you a very big method
with many switches, if and else. Not readable, not understandable (I refer understandable to things
which do not take longer than approx. 5 seconds to understand), not good at all.
So the next step would be splitting the menu into 3 different methods. Now we have three menu
implementations which should have the same shape/coding style. Why? Because then it takes less
time to understand the whole source code. If we understand the main menu, we instantly know how
the change product menu and the product menu works.
public void mainMenu() {
// get inputs
// switch to menu points
}
public void mainMenu() {
// get inputs
// switch to menu points
}
public void productMenu() {
// get inputs
// use if else to go to menu points
}
public void productMenu() {
// get inputs
// switch to menu points
}
public void changeProductMenu() {
// get inputs with separate method
// use a switching method
}
public void changeProductMenu() {
// get inputs
// switch to menu points
}
The code format is another important thing which clears up code and helps to read and maintain it.
Use line breaks, they don’t cost anything. And don’t be scared to have 100 lines more than your
fellow student just because you made breaks between a variable and the function head. Try to find a
code format which is fast readable and not exhausting and use this style through you entire code.
The next step would be, to get the correct order of the code.
The first 5 points are always public than private and alphabetically.
1. First Constants grouped together
2. Then final fields
3. Followed by normal fields
4. Public static methods
5. private static methods
6. Then either you sort your function alphabetically (public than private).
Or you sort them in a logically way.
- Page 17/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Commenting
public void mainMenu() {
int a = 2; // init local variable
int b = 5; // init local variable
a += b; // a = a+b
System.out.println(a); // print a
}
Commenting in java should be used only to comment the algorithm but not the code. But what is
the difference between those?
This is commenting your code because the comments refer to the code, not to what are you doing.
public void mainMenu() {
int a = 2;
int b = 5;
a += b; // adding b to a
System.out.println(a);
}
This would be an example for commenting the algorithm. But since adding isn’t an algorithm at all
we would not write this comment in a real source code.
If you write a complex matrix algorithm then you definitely want to comment what happens in your
code like: “getting scalar product of the row vectors”. And through good naming we would see that
we have a vectorIndex and a columnIndex which work together within your two loops.
- Page 18/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
b) Developing a sample solution for Assignment 6
In this part we will develop a solution for assignment 6 in a systematic way. We will slightly alter
the feature input but for the rest it will be the same as for the exercise.
We will also try to implement the things we said in the previous section.
Problem: Implement a shop with products. Each product can have features. You also need to
implement a user interface.
1. Identify the program structure
The structure is more or less obvious.
Classes:
§ Main Class: Contains the user interface and sets up our store
§ Shop Class: Represents a shop and contains products
§ Product Class: Represents a product and contains its features
§ Feature Class: Represents a feature
So now that we know how much classes we have and which purpose they will serve we start the
implementation. I tend to start by the easier classes and go further up but that’s just a matter of
taste.
Feature Class
This class will contain a string name and a string description and appropriate setters getters.
Because some features are self-explaining we allow the empty string for description. Nevertheless
we always want a none-empty-string as name.
public Feature(String name, String description) {
setName(name);
setDescription(description);
}
The constructor will be public because everybody should be able to use this class. But if somebody
wants to use this class he must provide a name and a description (the empty standard constructor
doesn’t exist from now).
public boolean setName(String name) {
// name is a mandatory field so we set the object reference as name if
// the string is empty
if (name == null || name.isEmpty()) {
if (this.name == null) {
this.name = this.toString();
}
return false;
} else {
this.name = name;
return true;
}
}
Because we have restriction on the name we call the setName method which already implements
those restrictions and through that, we save redundant code.
Because our prerequisite said that the name should always be a none-empty-string we need to check
the parameter name if it’s null or empty. If it is we set the name to the object reference. And return
false. So it is guaranteed that we never have an empty string as name. With the return value we told
the caller that we couldn’t set his desired name. If there was already a valid name, it stays the object
name.
The purpose of a setter is to control the change of a variable. Therefore you definitely want to make
your checks in the setters. If you make additional checks within the caller, that’s ok. But since the
setters ensure a legal state of the object we can save us the additionally checking.
- Page 19/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Product Class
This class represents a single product. Each product has a defined amount of features which we will
save in an array. We will need getters and setters for the fields and add/remove methods for the
features.
public static final int
MAX_FEATURE_AMOUNT = 10;
private
private
private
private
private
final Feature[] features;
final long productNumber;
String name;
int nextFreeFeatureSlot = 0;
double price;
First of all we set up our fields. We use a constant for the amount of the features which directly
indicates that our features array will be immutable. Our product number will not have a setter
therefore it can never be changed and so it is immutable. We use an extra integer to point at the next
free position within our features array. That saves us the iteration over the array if we want to set a
new feature.
public boolean addFeature(final Feature feature) {
// Checking if there is enough space
if (nextFreeFeatureSlot >= features.length) {
return false;
}
if (feature != null) {
features[nextFreeFeatureSlot] = feature;
nextFreeFeatureSlot++;
return true;
}
return false;
}
The getters and setters will be not only logical coded in the same way but also the code format will
be the same. This is how we implement the addFeature() method.
public boolean removeFeature(final int index) {
// remove the feature if it is valid, and trim the array
if (index >= 0 && index < features.length && features[index] != null) {
features[index] = null;
nextFreeFeatureSlot = Main.trimArray(features);
return true;
}
return false;
}
The remove method sets the feature to null if the index is legal. After we cleared the element we
want to clean up the array because we don’t want to have a fragmented array.
Therefore we will use a self-implemented static util function. As you see, util functions are most of
the time very generic and static. Why? Trim array takes an object array so we can put every
possible array of an object into the function. It is static because it’s an util function, which
implements a specific algorithm on a specific structure. It’s like a small sub program. Think of the
Math.random(). It’s a small subprogram which returns you something, but you do not want to
initialize a Math object each time you want that something. So we make it static.
- Page 20/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Shop Class
There is nothing to say about this class. Because we code in a regular way, this class looks nearly
the same as the Product class (code format, logic).
Main Class
This class contains the user interface, which always involves a lot of if else switches and so on. To
get a good structured code we try to implement it in a way, so we can understand the code fast and
that in a years’ time.
public static void main(final String[] args) {
final Main controller = new Main("Electronics & More");
controller.run();
}
First we need to construct the Main object in the main method.
public Main(final String shopName) {
shop = new Shop(shopName);
final Product[] products = createSampleProducts();
for (final Product p : products) {
shop.addProduct(p);
}
}
This object is the controller because the shop logic is implemented in this class. Feel free to further
enhance the code by splitting the business logic in a separate class, leaving the Main class with util
functions and the main method. After constructing it we call the run() method which starts the shop.
In the constructor we initialize the shop, create some product presents (just for an example) and add
the product to the shop. For such things the for-each loop is comfortable. Now let’s get to the hard
part.
private void run() {
boolean exit = false;
int selection;
while (!exit) {
System.out.println(DIVIDER + "\n\t" + shop.getName() + "\n"
+ DIVIDER + "\n");
// Get user selection
selection = mainMenu();
// Switch of the main menu
switch (selection) {
case 1:
printProducts();
break;
case 2:
addProduct();
break;
case 3:
removeProduct();
break;
// continued on next page…
- Page 21/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
case 4:
modifyProduct();
break;
case 5:
exit = true;
break;
}
}
}
This is the main loop of the program. It gets the user input and switches between the selections. The
mainMenu() method prints the menu points and returns the selected menu item. So this part wasn’t
really that hard.
private void modifyProduct() {
// Get user selection
final int productIndex = productMenu();
if (productIndex != -1) {
final Product product = shop.getProduct(productIndex);
printProductDetails(product);
final int selection = modifyMenu();
// Switch of the modification menu
switch (selection) {
case 1:
changeProductName(product);
break;
case 2:
changeProductPrice(product);
break;
case 3:
changeProductFeature(product);
break;
}
}
}
The modifyProduct method is built up exactly the same way.
private void changeProductFeature(final Product product) {
// Get user selection
final int selection = changeProductFeatureMenu(product);
// Switch of the feature menu
switch (selection) {
case 1:
if (product.getFeatures()[0] != null) {
removeFeature(product);
} else {
System.out.println("No features available! \n");
}
break;
case 2:
addFeature(product);
break;
}
}
The same accounts for the changeProductFeature menu.
- Page 22/23 -
2013-01-08
A. Riener/Institute for Pervasive Computing
Now that we have three menus, each menu item is just implemented in a separate method. This will
keep the switch clean of implementation which helps if you need to debug something or if you want
to extend the menus.
Now that the program code is finished we will test each menu item on several correct and incorrect
inputs and hope that we find as much mistakes as possible. It’s very likely (and normal) that you
code will contain bugs, so don’t hesitate asking a fellow student to read over your code. Both will
profit from that.
Acknowledgements
Thanks to all the course instructors and TA’s (in particular Hannes Thaller) for preparing this
tutorial/systematic development of the sample solution.
- Page 23/23 -