The NetRexx Tutorial
- More on NetRexx Classes
NetRexx Tutorial - More on NetRexx Classes


More on NetRexx Classes

Introduction

In this chapter we'll look at some "details" we intentionally left uncovered in the previous discussion.

Basic Concepts

Patterns and Pattern Design

Pattern Design is used to sketch a solution to some particular Object Oriented problem. It has probably already happened to you (as it did to me) to think: "I've already solved this problem (or a similar one) in the past." Then you rush to your code and try to find the solution again. If I'm allowed to make such comparison, then, "Design Patterns" stand to "Object Oriented Programming" as "Algorithms" stand to "Procedural Programming". Even further, Gamma, Helm, Johnson and Vlissides text stands to "Design Patterns" as Knuth's stands to "Algorithms".

The key issue is to make your software reusable. Using Design Patterns, you not only make it such, but you also reuse other's people efforts to find the right solution.

Usage of Abstract Classes

A Simple (?) problem

Let us consider a class hierarchy for a simple problem: we consider the "universe" of 2D rectangular objects, where we'll find Rectangles and Squares. A Venn diagram representing our "universe" might be useful:

 
  +---------------------------------------------+ U
  |                                             | N
  | RECTANGLE                                   | I
  |                                             | V
  |                 +--------------+            | E
  |                 |              |            | R
  |                 |      SQUARE  |            | S
  |                 |              |            | E
  |                 +--------------+            |
  +---------------------------------------------+

                                         Venn diagram of the
                                  "universe" class RECTANGLE
                                    with a subclass (SQUARE)
 

Making an Object Model

Recalling what we saw in the previous section, we can try to implement the above diagram using NetRexx. The first thing I'd think of is to make a Rectangle class, and have Square defined as a subclass of Rectangle.

Let's make an Object Model for this diagram:

 
  +--------------+
  |              |
  | RECTANGLE    |
  |              |<-----( RE1 )
  +--------------+
        |
        *
       * *
      *****
        |
  +--------------+
  |              |
  | SQUARE       |
  |              |<-----( SQ1 )
  +--------------+
 

Note that, in our diagram:

So, from our picture we can say phrases like: the class "SQUARE" "is-a-subclass-of" the class "RECTANGLE", or the object "SQ1" is an instance of the class "SQUARE".

Implementing it in NetRexx

The actual implementation is trivial: so just look at the code.

 
+----------------------------------------------------------------------+
| -- abex1.nrx                                                         |01
| -- Implements Rectangles and Squares                                 |02
| --                                                                   |03
| class abex1 public                                                   |04
|   properties public                                                  |05
|                                                                      |06
|   method main(args=String[]) public static                           |07
|     args = args                                                      |08
|                                                                      |09
|     RE1 = _Rectangle(1,2)                                            |10
|     say RE1.area()                                                   |11
|                                                                      |12
|     SQ1 = _Square(2)                                                 |13
|     say SQ1.area()                                                   |14
|                                                                      |15
|     exit 0                                                           |16
|                                                                      |17
| class _Rectangle                                                     |18
|   properties public                                                  |19
|     length                                                           |20
|     width                                                            |21
|   method _Rectangle(l=Rexx,w=Rexx) public                            |22
|     length = l                                                       |23
|     width = w                                                        |24
|   method area public                                                 |25
|     return this.length*this.width                                    |26
|   method set_width(w=Rexx) public                                    |27
|     this.width = w                                                   |28
|   method set_length(l=Rexx) public                                   |29
|     this.length = l                                                  |30
|   method perimeter public                                            |31
|     return 2*(this.length+this.width)                                |32
|                                                                      |33
| class _Square extends _Rectangle                                     |34
|   method _Square(s=Rexx) public                                      |35
|     super(s,s)                                                       |36
|   method area public                                                 |37
|     return this.length*this.length                                   |38
|   method perimeter public                                            |39
|     return 4*this.length                                             |40
+----------------------------------------------------------------------+
                                                               abex1.nrx
Download the source for the abex1.nrx example

Critics to the above implementation

There is a series of problems with the above implementation; I analyse them in order of increasing importance.

Using Abstract Class

To correctly represent the Venn Diagram, we MUST use three classes. The universe class will be an "abstract" class, that we can call 2DSHAPE.

Let's revise our Object Model:

 
              +--------------+
              |              |
              | 2DSHAPE      |
              |              |
              +--------------+
                   |
                   *
                  * *
        +--------*****-----------------+
        |                              |
        |                              |
+--------------+                      +--------------+
|              |                      |              |
| SQUARE       |                      | RECTANGLE    |
|              |<--( SQ1 )            |              |<--( RE1 )
+--------------+                      +--------------+
 

Implementation

In order to create an abstract class (i.e. a class that contains at least an abstract method), we use the keyword abstract (note that in C++ the keyword virtual is used).

That's how you'd implement in NetRexx:

 
+----------------------------------------------------------------------+
| -- abex2.nrx                                                         |01
| -- abstract class example                                            |02
| --                                                                   |03
| class abex2 public                                                   |04
|                                                                      |05
|   method main(args=String[]) public static                           |06
|     args = args                                                      |07
|     R1 = _Rectangle(2,3)                                             |08
|     say R1.area()                                                    |09
|     S1 = _Square(3)                                                  |10
|     say S1.area()                                                    |11
|     say 'You defined' _2Dshape.nobjects 'shapes.'                    |12
|     exit 0                                                           |13
|                                                                      |14
| class _2Dshape abstract                                              |15
|   properties public static                                           |16
|     nobjects = 0                                                     |17
|   method _2dShape() public                                           |18
|     nobjects = nobjects+1                                            |19
|   method area public returns Rexx abstract                           |20
|   method perimeter public returns Rexx abstract                      |21
|                                                                      |22
| class _Rectangle extends _2Dshape                                    |23
|   properties private                                                 |24
|     length                                                           |25
|     width                                                            |26
|   method _Rectangle(l=Rexx,w=Rexx) public                            |27
|     super()                                                          |28
|     length = l                                                       |29
|     width = w                                                        |30
|   method area public                                                 |31
|     return length*width                                              |32
|   method perimeter public                                            |33
|     return 2*length*width                                            |34
|                                                                      |35
| class _Square extends _2Dshape                                       |36
|   properties private                                                 |37
|     side                                                             |38
|   method _Square(s=Rexx) public                                      |39
|     super()                                                          |40
|     side = s                                                         |41
|   method area public                                                 |42
|     return side*side                                                 |43
|   method perimeter public                                            |44
|     return 4*side                                                    |45
|                                                                      |46
+----------------------------------------------------------------------+
                                                               abex2.nrx
Download the source for the abex2.nrx example

Interfaces

 
 *** This section is: 
  
 *** and will be available in next releases

Dynamical Interfaces

Sample code

The interface part will look as follows:

 
+----------------------------------------------------------------------+
| -- runnable.nrx                                                      |01
| --                                                                   |02
| class runnable interface                                             |03
|   method run() public                                                |04
+----------------------------------------------------------------------+
                                                            runnable.nrx
Download the source for the runnable.nrx example

 
+----------------------------------------------------------------------+
| -- dyna2.nrx                                                         |01
| --                                                                   |02
| class dyna2 public                                                   |03
|                                                                      |04
|   method main(args=String[]) public static                           |05
|     arg = Rexx(args)                                                 |06
|     do                                                               |07
|       r = runnable;                                                  |08
|       un = Class.forName(arg);                                       |09
|       r = runnable un.newInstance()                                  |10
|       r.run()                                                        |11
|     catch e= Exception                                               |12
|       say e                                                          |13
|     end                                                              |14
|     exit 0                                                           |15
|                                                                      |16
| class test1 implements runnable                                      |17
|   method run public                                                  |18
|     say 'Hello from class TEST1'                                     |19
|                                                                      |20
| class test2 implements runnable                                      |21
|   method run public                                                  |22
|     say 'Hello from class TEST2'                                     |23
|                                                                      |24
+----------------------------------------------------------------------+
                                                               dyna2.nrx
Download the source for the dyna2.nrx example

 
+----------------------------------------------------------------------+
| -- dyna3.nrx                                                         |01
| --                                                                   |02
| class dyna3 public                                                   |03
|                                                                      |04
|   method main(args=String[]) public static                           |05
|     arg = Rexx(args)                                                 |06
|     loop forever                                                     |07
|       say 'Enter Class name (A,B,C) or quit'                         |08
|       parse ask.upper() name                                         |09
|       if name = 'QUIT' then leave                                    |10
|       do                                                             |11
|         r = runnable;                                                |12
|         un = Class.forName(name);                                    |13
|         r = runnable un.newInstance()                                |14
|         r.run()                                                      |15
|       catch e= Exception                                             |16
|         say e                                                        |17
|       end                                                            |18
|       say 'There are' A.n 'instances for A.'                         |19
|       say 'There are' B.n 'instances for B.'                         |20
|       say 'There are' C.n 'instances for C.'                         |21
|     end                                                              |22
|     say 'End.'                                                       |23
|     exit 0                                                           |24
|                                                                      |25
| -- class A                                                           |26
| --                                                                   |27
| class A implements runnable                                          |28
|   properties static                                                  |29
|     n = 0                                                            |30
|   method A public                                                    |31
|     n = n+1                                                          |32
|   method run public                                                  |33
|     say 'Hello from class A'                                         |34
|                                                                      |35
| -- class B                                                           |36
| --                                                                   |37
| class B implements runnable                                          |38
|   properties static                                                  |39
|     n = 0                                                            |40
|   method B public                                                    |41
|     n = n+1                                                          |42
|   method run public                                                  |43
|     say 'Hello from class B'                                         |44
|                                                                      |45
| -- class C                                                           |46
| --                                                                   |47
| class C implements runnable                                          |48
|   properties static                                                  |49
|     n = 0                                                            |50
|   method C public                                                    |51
|     n = n+1                                                          |52
|   method run public                                                  |53
|     say 'Hello from class C'                                         |54
+----------------------------------------------------------------------+
                                                               dyna3.nrx
Download the source for the dyna3.nrx example

This is what we get running dyna3:

 
..............................................................
Enter Class name (A,B,C) or quit
A
Hello from class A
There are 1 instances for A.
There are 0 instances for B.
There are 0 instances for C.
Enter Class name (A,B,C) or quit
A
Hello from class A
There are 2 instances for A.
There are 0 instances for B.
There are 0 instances for C.
Enter Class name (A,B,C) or quit
A
Hello from class A
There are 3 instances for A.
There are 0 instances for B.
There are 0 instances for C.
Enter Class name (A,B,C) or quit
B
Hello from class B
There are 3 instances for A.
There are 1 instances for B.
There are 0 instances for C.
Enter Class name (A,B,C) or quit
C
Hello from class C
There are 3 instances for A.
There are 1 instances for B.
There are 1 instances for C.
Enter Class name (A,B,C) or quit
B
Hello from class B
There are 3 instances for A.
There are 2 instances for B.
There are 1 instances for C.
Enter Class name (A,B,C) or quit
quit
End.
..............................................................
 
 *** This section is: 
  
 *** and will be available in next releases

Patterns

The Singleton

The idea of Singleton is simple: we want to make sure that a class has ONLY one instance, and we want to provide a global point of access to it.

The structure is (GAMMA, 96, p. 127)

 
+----------------------------+
| Singleton                  |
+----------------------------+          +----------------------\
|   static Instance()   *-------------> | return uniqueInstance|
|   (...)                    |          +----------------------+
|   SingletonOperation()     |
|   GetSingletonData()       |
|                            |
|                            |
|                            |
+----------------------------+
|   static UniqueInstance    |
|   (...)                    |
|   singletonData            |
|                            |
|                            |
+----------------------------+

NetRexx Implementation of the Singleton

The NetRexx implementation of the Singleton Pattern might look like:

 
+----------------------------------------------------------------------+
| -- Singleton.nrx                                                     |01
| --   NetRexx Implementation of Singleton                             |02
| --   see GAMMA, 1996, p.127                                          |03
| --                                                                   |04
| class Singleton public                                               |05
|                                                                      |06
|   properties private static                                          |07
|     _instance = Singleton NULL                                       |08
|                                                                      |09
|   method Singleton() private                                         |10
|                                                                      |11
|   method Instance() returns Singleton public static                  |12
|     if _instance = NULL then                                         |13
|       do                                                             |14
|         _instance = Singleton()                                      |15
|         return _instance                                             |16
|       end                                                            |17
|     return _instance                                                 |18
+----------------------------------------------------------------------+
                                                           Singleton.nrx
Download the source for the Singleton.nrx example

Let's look at it closely. The first "uncommon" feature we find is:

 
   method Singleton() private
 

i.e. the constructor is declared as private. Clients will not be capable to access it with a normal:

 
   s = Singleton()
 

Instead, they're forced to use the Instance() member function, declared as static.

This means that the clients will need to write:

 
   s = Singleton.Instance()
 

in order to get the unique Singleton's instance.

 
 *** This section is: 
  
 *** and will be available in next releases

An history class.

Description of the problem

It is sometimes interesting to record the actions that an user enters when dealing with an interactive program. This is, for example, the case of the history command in an UNIX shell.

First approach.

When I dealt for the first time with an implementation of an history command, my solution was to define a history buffer (with his length):

 
  properties public static
    cmdbuf = Rexx(")
    cmdbufl = 20
 

and 2 methods to save/dump the history:

 
+----------------------------------------------------------------------+
| -- method......: historyd                                            |44
| -- purpose.....: display the history                                 |45
| --                                                                   |46
|   method historyd(cur=Rexx) public static                            |47
|     if cur < cmdbufl                                                 |48
|       then st = 1                                                    |49
|       else st = cur-cmdbufl                                          |50
|     loop i = st to cur-1                                             |51
|       say i.right(5) cmdbuf[i]                                       |52
|     end                                                              |53
|                                                                      |54
+----------------------------------------------------------------------+
                                            xshell1.nrx(Method:historyd)
Download the complete source for the xshell1.nrx library

 
+----------------------------------------------------------------------+
| -- method......: history                                             |55
| -- purpose.....: history                                             |56
| --                                                                   |57
|   method history(a=Rexx,n=Rexx) public static                        |58
|     if a <> '' then                                                  |59
|       do                                                             |60
|         cmdbufl = a                                                  |61
|       end                                                            |62
|     else                                                             |63
|       do                                                             |64
|         historyd(n)                                                  |65
|       end                                                            |66
|                                                                      |67
+----------------------------------------------------------------------+
                                             xshell1.nrx(Method:history)
Download the complete source for the xshell1.nrx library

In the main loop, I was calling saving the entered command in the buffer

 
  cmdbuf[cmdno] = todo
  cmdno = cmdno+1
 

The history class

The commands are saved in the history buffer inside a circular buffer

 
+----------------------------------------------------------------------+
| -- method......: save                                                |66
| -- purpose.....:                                                     |67
| --                                                                   |68
|   method save(entry=Rexx) public                                     |69
|     k = lastrec // maxrec                                            |70
|     if record[k] <> NULL then                                        |71
|       do                                                             |72
|         if entry = record[k]                                         |73
|           then return                                                |74
|       end                                                            |75
|     lastrec = lastrec+1                                              |76
|     k = lastrec // maxrec                                            |77
|     record[k] = entry                                                |78
|                                                                      |79
+----------------------------------------------------------------------+
                                                history.nrx(Method:save)
Download the complete source for the history.nrx library

 
+----------------------------------------------------------------------+
| -- method......: dump                                                |45
| -- purpose.....:                                                     |46
| --                                                                   |47
|   method dump(n=Rexx) public                                         |48
|     first = lastrec - n + 1                                          |49
|     loop i=first to lastrec                                          |50
|       k = i// maxrec                                                 |51
|       if record[k] = NULL then iterate                               |52
|       if record[k] = ''   then iterate                               |53
|       say i.right(5) record[k]                                       |54
|     end                                                              |55
|                                                                      |56
+----------------------------------------------------------------------+
                                                history.nrx(Method:dump)
Download the complete source for the history.nrx library

 
+----------------------------------------------------------------------+
| -- method......: retrieve                                            |57
| -- purpose.....:                                                     |58
| --                                                                   |59
|   method retrieve(n=Rexx) public returns Rexx                        |60
|     if n < lastrec - maxrec then return "                           |61
|     if n > lastrec then return "                                    |62
|     k = n// maxrec                                                   |63
|     return record[k]                                                 |64
|                                                                      |65
+----------------------------------------------------------------------+
                                            history.nrx(Method:retrieve)
Download the complete source for the history.nrx library
 
  his = history(100)

  loop
    -- get user input
    his.save(USER_INPUT)

  end
 

Additional sources of information

You can find additional information about patterns at:

 
http://st-www.cs.uiuc.edu/users/patterns/
 

with some tutorial information at:

 
http://www.enteract.com/~bradapp/docs/patterns-intro.html
http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/patterns/
 

Chapter Summary

 
 *** This section is: 
  
 *** and will be available in next releases


File: nr_12.html.

The contents of this WEB page are Copyright © 1997 by Pierantonio Marchesini / ETH Zurich.

Last update was done on 18 May 1998 21:47:47(GMT +2).