Previous Page | Next Page

SAS Object-Oriented Programming Concepts

Interfaces

Interfaces are groups of method declarations that enable classes to possess a common set of methods even if the classes are not related hierarchically. An interface is similar to a class that contains only method declarations.

A class can either support or require an interface. A class that supports an interface must implement all of the methods in the interface. A class that requires an interface can invoke any of the methods in the interface.

Suppose you have the following interface:

interface I1;
  M1: method;
endinterface;

If class A supports the interface, then it must implement the method M1:

class A supports I1;
  M1: method;
    put 'Implementation of M1';
  endmethod;
endclass;

Class B requires the interface, which means that it can invoke the methods declared in the interface.

class B requires I1;
  M2: method;
     dcl I1 myObj = _new_ I1;
     myObj.M1();
  endmethod;
endclass;

Interfaces are especially useful when you have several unrelated classes that perform a similar set of actions. These actions can be declared as methods in an interface, and each class that supports the interface provides its own implementation for each of the methods. In this way, interfaces provide a form of multiple inheritance.

A class can be defined to support or require one or more interfaces. If two components share an interface, they can indirectly call each others' methods via that interface. For example, model/view component communication is implemented with the use of interfaces. The model typically supports the interface, whereas the view requires the same interface. The interfaces for the components must match before a model/view relationship can be established. A class stores interface information as a property to identify whether it supports or requires an interface. Refer to SAS Guide to Applications Development for more information about model/view communication.

Although classes that support or require an interface are often used together, they are still independent components and can be used without taking advantage of an interface.


Defining Interfaces

You define interfaces with the INTERFACE statement block:

INTERFACE interface-name
<EXTENDS interface-name>
</ (interface-optional-clause)>;
<limited-method-declaration-statements>
ENDINTERFACE;
For more information about defining interfaces, see and INTERFACE.

Example

The following INTERFACE block declares two methods for reading and writing data.

interface Reader;
  Read: method return=string;
  Write: method data:string;
endinterface;

Only the method declarations are given in the INTERFACE block. The method implementations are given in any class that supports the interface.

For example, the Lst and Ddata classes both implement the Read and Write methods. These classes support the Reader interface. In the Lst class, these methods read and write items from and to an SCL list.

class Lst supports Reader;
  dcl list listid;
  dcl num cur n rc;

  /* Override the class constructor. */
  /* Create a new list.              */
  Lst: method/(state='o');
    listid = makelist();
    cur = 0;
    n = 0;
  endmethod;

  Read: method return=string;
    if (cur >= n) then do;
      put 'End of file';
      return "";
      end;
    else do;
      cur + 1;
      /* Get the current item from the list. */
      dcl char item;
      item=getitemc(listid,cur);
      return item;
    end;
  endmethod;

  Write: method c:string;
    n + 1;

    /* Insert a new item into the list. */
    rc=insertc(listid,c,-1);
  endmethod;

endclass;

The method implementations in the Ddata class read and write data from and to a SAS table.

class Ddata supports Reader;
  protected num fid;
  protected num obs n;
  dcl num rc;

  /* Override the class constructor. */
  /* Use the open function to open a SAS table. */
  Ddata: method name: string mode: string;
    fid = open(name, mode);
    obs = 0;
    n = 0;
  endmethod;

  Read: method return=string;
    if (obs >= n) then do;
      put 'End of file';
      return "";
    end;
    else do;
      dcl string c;

      /* Fetch an observation from the table. */
      obs + 1;
      rc=fetchobs(fid, obs);

      /* Get the contents of table column 1. */
      c = getvarc(fid, 1);
      return c;
    end;
  endmethod;

  Write: method c:string;
    dcl num rc;

    /* Add a new row to the table and         */
    /* write the contents of C into column 1. */
    rc=append(fid);
    call putvarc(fid, 1, c);
    rc = update(fid);
    n + 1;
  endmethod;

endclass;

Using the interface, you can read and write data without knowing the data source. In the following example, the Read class implements method M, which calls the method that was declared in the Reader interface. The interface determines which method implementation is executed.

class Read;
  M: method r:Reader;

    /* Write a string to the data source, */
    /* then read it back.                 */
    r.write("abc");
    put r.read();
  endmethod;
endclass;

The following labeled program section reads and writes data to both a list and a SAS table. This code passes a Lst class and a Ddata class to the Read class, which treats the list and the table in the same way. The data is read and written transparently. The Read class does not need to know what the actual implementation of the Reader is -- it only needs to know the interface.

init:
  dcl Lst L = _new_ Lst();
  dcl Ddata D = _new_Ddata("test","un");
  dcl read R = _new_ read();
  
  R.M(L);
  R.M(D);
return;

Previous Page | Next Page | Top of Page