COMP 3670 - Understanding Objects

Alex Bunardzic, British Columbia Institute Of Technology (BCIT)

Code examples:

In order to illustrate the concepts presented during Lecture #5, we have introduced a bare-bones Java application. This application is supposed to demonstrate the use of interfaces, inheritance, and the built-in pessimistic assumptions that come as part of the distributed object platform ("if anything can go wrong, it will").

We've started with an extremelly simple interface SimpleAssignment. It has only one prescribed behavior (simpleCapability()). This interface will act on behalf of the service provider objects we will decide to implement. The service consumer (or, the client) will talk to this interface only.

interface SimpleAssignment{
     public void simpleCapability();
}


We have decided to implement the functionality prescribed in SimpleAssignment interface by creating a SimpleImplementation class. This class implements the simpleCapability() behavior (we are faking this behavior by simply printing a short message to the console).

class SimpleImplementation implements SimpleAssignment {
     public void simpleCapability(){
          System.out.println("from inside SimpleImplementation -- simple capability");
     }
}


We have then decided to play with inheritance, and to extend the capability of the SimpleImplementation class. The new class is called MoreComplicatedImplementation, and it introduces a new behavior, notSoSimpleCapability().

class MoreComplicatedImplementation extends SimpleImplementation {
     public void simpleCapability(){
          System.out.println("from inside MoreComplicatedImplementation -- simple capability");
     }

     public void notSoSimpleCapability(){
          System.out.println("from inside more complicated impl -- not so simple capability");
     }
}


Furthermore, we have introduced yet another more specialized class, that elaborates upon the capabilities of MoreComplicatedImplementation. That class was, quite frivolously, named EvenMoreComplicatedImpl. It extends (subclasses or inherits) from the MoreComplicatedImplementation

class EvenMoreComplicatedImpl extends MoreComplicatedImplementation {
      public void simpleCapability(){
           System.out.println("from inside EvenMoreComplicatedImplementation -- simple capability");
      }
}


Finally, our consumer object (the Client class) simply uses the interface to send messages to the underlying implementations. Note how the implementation is not being mentioned in the client's code. The only thing that's being mentioned there is the SimpleAssignment interface -- this is the bias of our system. In other words, the system is calibrated to be dependent on the presence of the SimpleAssignment interface. Everything else is completely interchangeable (flexible).

The particular implementation of the service will be defined outside of the application. In this case, we will simply pass it in as a command line parameter. In real life, it will be defined in a separate *.properties file, or in a database. That way, the implementation is controllable by the application administrator (or, the object librarian).

class Client {
     public static void main(String[] args) {
          try{
               SimpleAssignment simpleAss = (SimpleAssignment)Class.forName(args[0]).newInstance();
               simpleAss.simpleCapability();
          }
          catch(Exception e){
               System.out.println("Problem in client " + e);
          }
     }
}

Note how the client will try to talk to the interface. This is due to the pessimistic nature of the language, which has a built-in awareness that things may, in all likelihood, go wrong. If you remove the try/catch block surrounding the attempt to talk to the service provider, the Client class will simply refuse to compile.