|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 7
Now that you have the DiagnoseStartStop and Counter interfaces, you can develop a program that tracks how many times you fail at starting a washing machine. Listing 5 does just
that:
Listing 5. FaultyAppliance.java
// FaultyAppliance.java
class Appliance implements Counter, DiagnoseStartStop
{
private int count;
private String brand;
protected boolean started;
Appliance (String brand)
{
this.brand = brand;
}
String getBrand ()
{
return brand;
}
public void increment ()
{
count++;
}
public int getCount ()
{
return count;
}
public void start ()
{
increment ();
}
public void stop ()
{
}
public boolean isStarted ()
{
return started;
}
}
class WashingMachine extends Appliance
{
WashingMachine (String brand)
{
super (brand);
}
public void start ()
{
if (isStarted ())
{
System.out.println ("Washing machine already running.");
return;
}
if (rnd (4) > 1)
{
System.out.println ("Trying to start washing machine.");
super.start ();
}
else
{
started = true;
System.out.println ("Washing machine is running.");
}
}
public void stop ()
{
if (started)
{
started = false;
System.out.println ("Washing machine is stopped.");
}
else
System.out.println ("Washing machine already stopped.");
}
// Return a random number between 0 and limit - 1 (inclusive).
int rnd (int limit)
{
return (int) (Math.random () * limit);
}
}
class FaultyAppliance
{
public static void main (String [] args)
{
WashingMachine wm = new WashingMachine ("Maytag");
for (int i = 0; i < 10; i++)
wm.start ();
if (wm.isStarted ())
wm.stop ();
System.out.println ("Number of faulty start attempts: " +
wm.getCount ());
}
}
FaultyAppliance's main() method creates a WashingMachine object and tries to start the washing machine 10 times. If the washing machine starts, it must stop. If the first attempt
to start the washing machine succeeds, getCount() returns zero. Otherwise, that method returns the number of faulty start attempts. To accomplish its simulation, FaultyAppliance uses Math's random() method, which returns a random number that ranges from 0.0 to (almost) 1.0. By multiplying random()'s return value by some limit, and by converting the result to an integer, it is possible to generate an integral random number
greater than or equal to zero and less than some limit. (I will discuss Math and its methods in a future column.)
The Appliance class inherits from both the Counter and DiagnoseStartStop interfaces. In contrast to the general use of multiple implementation inheritance, Appliance's multiple interface inheritance is safe. To see why, let's compare both inheritance approaches. We begin with a look at
read/write variables and conclude with a look at methods.
What is wrong with multiple implementation inheritance in the context of read/write variables? To answer that question, keep
in mind that the compiler must generate instructions that the JVM executes to allocate memory for a variable. The amount of
memory the JVM allocates depends on the variable's type. Suppose two superclasses declare a read/write variable with the same
name but different types and/or initial values. If Java permitted a subclass to inherit from both superclasses, the compiler
would face a dilemma: should it assume the first type (and, possibly, initial value) or the second type (and, possibly, initial
value)? A subclass's type implementation is fixed and cannot accommodate both types, thus, the dilemma. For example, suppose
the subclass contains x = 2;, and one superclass declares x to be of integer type, whereas the other superclass declares x to be of double-precision floating-point type. Does the compiler generate instructions that assign a 32-bit twos-complement
bit sequence -- representing an integer -- to a 32-bit memory location? Or does it generate instructions that assign a 64-bit
IEEE-754 format floating-point bit sequence -- representing a double-precision floating-point value -- to a 64-bit memory
location? That problem exacerbates if each superclass contains a method that modifies its same-named variable according to
the variable's type. Assuming a subclass inherits both methods, the compiler must deal with two different type implementations
for the same variable.