Thoughts about Java and more

Menu

Test-Driven Teaching – 3. Object Oriented Programming

Introduction

In the previous sections we learned how to create a simple Java program and tested it. We mainly did procedural programming, while now we will learn how to better encapsulate functionality and data with the help of object oriented programming (OOP). The aim of OOP is mainly to provide better code re-use than it would be the case with procedural programming. With OOP it is easier to write large software and personally I think, it leads to better readable code.

An object is a self-contained entity which has its own collection of properties (ie. data) and methods (ie. operations) that encapsulate functionality into a reusable and dynamically loaded structure. After a class definition has been created as a prototype, it can be used as a template for creating new subclasses (via extends keyword) that add functionality. … Applications can request new objects of a particular class on demand via the new keyword.

Rename the InitialBlockGame class to BlockMan, for that you have to rename the file name too. This procedure is very easy with an IDE. In NetBeans just place your cursor under the class name right click->Refactor->Rename or just press CTRL R

Remove the static keyword from all occurences of the BlockMan class, except from the main(String[]) method

Remove the entire reset() method. We don’t need it, because we simple create a new object for every test

The line with ‘BlockMan.start();’ should be replaced with

BlockMan man1 = new BlockMan();
man1.start();

or with a shorter version:

new BlockMan().start();

Now we need to refactor the test cases and after the test compiles, it should pass as well. This shows one advantage and one disadvantage of test-driven development: you have to refactor all tests after refactoring which costs some time, but at the same time you can run those tests and make sure that all works as before.

Instead of calling the static start method of the BlockMan class we can now create a BlockMan object and invoke the start method of this object. Now it is simple to create and manage not only one man but several men:

(A good but not ideal comparison of Class/Object in the real world: A class could be compared to a rubber stamp and an object to the resulting images on the paper.)

Access Modifier

Additionally we should change the public access of the x and y variable. What does access mean? We learned in the previous post that we can use variables like x only in its block and sub-blocks, where it was defined. Now we used public before the variable declaration so that we can access (or ‘see’) the variable from all external code, which is called world in the following table. A short overview of this can be given:

Access Levels

Modifier

Class

Package

Subclass

World

public

Y

Y

Y

Y

protected

Y

Y

Y

N

no keyword == package access

Y

Y

N

N

private

Y

N

N

N

This table was taken from sun, where you can get more information about this topic.

With public acces we can retrieve y (the same is true for x)

assertEquals(1, man1.y);

and even initialize y:

man1.x = -100;

This is not good in the most cases and as you see here: the y value is not in its correct domain [0; 10). External code could change the variables without knowing the bounds or sth. else. E.g. the move-method is a better approach to change the variables x and y.

So, just make all variables private and provide publicmethods to manage initialization and retrieval of such a variable via setter and getter. Instead ‘public int x;’ you should do:

private int x;
// the getter is used for the retrieval
public int getX() {
return x;
}
// the setter is used for the initialization
public void setX(int someX) {
x = someX;
}

Now you can simply remove the setX method and ‘external code’ is not able to change x without the appropriate move method.

The x and y variables are sometimes called properties. To create such property-access-methods (getter and setter) with NetBeans press ALT INS and select Generate ‘Getter and Setter…’

Compare Your Project

We are near the finish of refactoring so check out the code of this third section to compare your refactored code with my code:

To compare the files go to the Projects window and select both files (hold CTRL). Then right-click->Tools->Diff

You will notice that I introduced two methods too: moveX and moveY to make our class easier to use. Also the border values could be now accessed from outside via getBorderX and getBorderY

equals != ==

For Java exists different comparison operations. The first most obvious comparison with the == operator isn’t always the correct one, because this operator compares only the references stored in an variable. For that please look into the class DifferentComparisonTest and you will see the statements:

Please look at the following picture where some of the previous variables are listed. The picture represents a simplified, logical view of the ‘current RAM‘ (the order of the variables and instances is not important).

The difference between the comparison mechanisms is also important in unit tests. Sometimes you will use:

assertTrue(obj == anotherObj);

But most of the time you will use

assertTrue(obj.equals(anotherObj));

or even better the assertEquals method which is already shipped by junit and which invokes the equals method under the hood:

assertEquals(obj, anotherObj);

Notes:

If your IDE is clever it will mark the equals method of your MyHousWithEquals class, because if you override equals you will normally need to override hashCode for a proper functionality of some datastructures. Under NetBeans press ALT ENTER to fix this automatically.

There exists even more comparison mechanisms as you can read in the javadoc here and here. Those interfaces are important for sorted datastructures like TreeSet or TreeMap.

Look at Unit Tests

Value vs. reference (‘pointers’) are explained in the ValueOrReferenceTest class

Loop constructs in the LoopExamples class

Important

As the last important information I would like to say that object oriented programming is not the heaven of programming. Please keep in mind that every approach has its drawbacks.

For example I would not introduce a Point variable within the BlockMan class instead of the two variables x and y. Why? Hmmh .. I think it is more convenient to directly access the x or y instead of getPoint().x or getPoint().y.

Another drawback is that for every object some memory overhead is introduced. Not a lot and it does not always matter, but you should keep this in mind for later projects!