Design Pattern in OO ABL – Part 3 of 3

Design Pattern in OO ABL – Part 3 of 3

INTRODUCTION

In programming, Design Patterns are used since a long time. The definition of the term was made in the book 'Design Patterns: Elements of Reusable Object-Oriented Software', in 1995.

 

This is the final part of our series on design pattern - we take a look at the pattern 'Fabric' and 'Proxy' in the context of OpenEdge Object Oriented ABL (OO ABL).

 

The first article is available here - it covers the pattern 'Builder', 'Singleton' and 'Multiton'*.

The second article is available here and talks about 'Lazy Loading' and 'Adapter'.

 

Download all three articles as single PDF and code sample 

PATTERN 6 – FACTORY/FABRIC (CREATIONAL PATTERN)

The Factory Pattern is a Creational Pattern, that allows to create an object without specifying the exact class that will be created.

 

Sometimes an application will create objects, which are similar but not exactly the same... To make the code more universal, the factory adds a layer to create these classes. You order something in the same area of interest and the fabric is producing this on demand - it's pretty simple ;)

Fabric Pattern – Class diagram

110

The creation specific logic and the details are hidden behind the factory. During run-time the created objects are accessed through an interface.

So the object is abstract during creation and during use. This diagram shows an example, where a factory is used to create transports with a wheel (car, bike).

In my example I have a factory creating some wheeler (car, bike) classes. I will not show the interface here, this is simple. It will be in the source package for download.

 

fWheeler.cls – Factory class: Instantiate class depending on wheeler type. The factory gives back the instance of a wheeler object of type iWheeler (the interface).

CLASS 06_Factory.fWheeler:

  ... conctructor etc. 

  // Create a car, bike or what else...
  METHOD PUBLIC iWheeler createWheeler ( cWheelerType AS CHARACTER ):
    DEFINE VARIABLE oWheeler AS iWheeler NO-UNDO.
    
    /* Instantiate various object types (which implement wheeler interface) */  
    CASE cWheelerType:
      WHEN "Car"  THEN oWheeler = NEW carWheeler().
      WHEN "Bike" THEN oWheeler = NEW bikeWheeler().
      OTHERWISE DO: 
        MESSAGE "Uups, unknown wheeler type: " cWheelerType
          VIEW-AS ALERT-BOX INFORMATION. 
        RETURN ERROR.
      END. 
    END CASE.
    
    // Start the wheeler building process
    oWheeler:buildWheeler().
    RETURN oWheeler.
    
  END METHOD.
...

bikeWheeler.cls – Implementation of bike wheeler: Create bike with common stuff and some bike specific methods. A similar class for cars is existing.

CLASS 06_Factory.bikeWheeler IMPLEMENTS 06_Factory.iWheeler: 

  properties from interface

  METHOD PUBLIC VOID buildWheeler(  ):
    // Call some bike specific stuff
    addPedal().
    cBuildResult = "I build a bike".
    cColor = "green".
    cType  = "bike".
  END METHOD.

  METHOD PUBLIC CHARACTER driveTest( INPUT cLevel AS CHARACTER ):
    // Run various tests somewhere in the area
    RETURN "Did bike test drive on level: " + cLevel.
  END METHOD.

  METHOD PUBLIC LOGICAL addPedal(  ):
    // Add a pair of glowing pedals to the bike
    cFeatures = "Professional races pedals".
    RETURN TRUE.
  END METHOD.
...

start.ptest program: This program (a .p file for my convenience) is using the factory for creating two wheelers. The handling of the different wheeler types is very simple for the user.

DEFINE VARIABLE ofWheeler  AS fWheeler NO-UNDO.
DEFINE VARIABLE oWheeler1  AS iWheeler NO-UNDO.
DEFINE VARIABLE oWheeler2  AS iWheeler NO-UNDO.

// First, create the factory
ofWheeler = NEW fWheeler().
// Then create two wheelers
oWheeler1  = ofWheeler:createWheeler("bike").
oWheeler2  = ofWheeler:createWheeler("car").


// Get some information from the wheelers
MESSAGE "Result of building wheeler: " oWheeler1:cBuildResult SKIP
        other
        "Result of building wheeler: " oWheeler2:cBuildResult SKIP
        other
  VIEW-AS ALERT-BOX INFORMATION TITLE"Build wheeler result"  

Factory – Advantages

      • Loose coupling between creator and created objects
      • Same creation code for every case (UI in this example)
      • Extensible, adding new UI types is simple
      • Testing (mock) is simple
      • Increase abstraction level (reduce maintenance)

Factory – Disadvantages

      • Add some complexity and code

 

Abstract Fabric:

A fabric is a class, creating objects of same or similar type. Often a fabric is used to create fabrics, then we talk about the Abstract Fabric pattern.

 

Conclusion:

(Abstract) Fabric is one of the top used design pattern, and useable without any problems in OpenEdge.

PATTERN 7 – PROXY (STRUCTURAL PATTERN)

The Proxy Pattern is a Structural Pattern, which will use one object as proxy for a second object, to mask something (complexity, security, location, instantiation time…) in another object.

 

The proxy is related to Adapter and Decorator (which I did not talk about in this series). The proxy is different to these, as it implements the same interface as the service object).

 

There are several scenarios, where proxies are used:

      • Smart proxy – Control load/unload/use of a central object or handle locking for a given to a unique resources object (e.g. wait until a transfer is ready before starting next).
      • Protective proxy – Control access to an object (security).
      • Remote proxy – Have a local object controlling a remote version of the same object (RMI).
      • Virtual proxy – Delay or avoid creation of a resource hungry (time, resources) object, so that the real creation is done during first functional access.
      • Simplify API to access a complex object.
      • Cache or log requests

Proxy Pattern – Class diagram

Diagram of a proxy pattern

proxySoapService.cls – Proxy class: This proxy creates an instance of the SOAP class. It will also check rights before and force HTTPS.

CLASS 07_Proxy.proxySoapService:

  define interface properties

  DEFINE VARIABLE oSoapServices  AS 07_Proxy.soapService NO-UNDO.
    
  // Create the service object and force https
  CONSTRUCTOR PUBLIC proxySoapService ():
    IF testUserRights() = TRUE THEN DO:
      oSoapServices = NEW 07_Proxy.soapService().
      oSoapServices:cProtocol = "SOAP".
      oSoapServices:lUseHttps = TRUE.
    END.
    ELSE RETURN ERROR.
  END CONSTRUCTOR.

  // Connect target URL
  METHOD PUBLIC VOID connectURL ( ).
    oSoapServices:cURL = THIS-OBJECT:cURL.
    IF oSoapServices:connectURL() THEN DO:
      cConnectResult = "Everything OK, connected : " + THIS-OBJECT:cURL.
    END.
    ELSE RETURN ERROR. 
  END METHOD.
  
  METHOD PRIVATE LOGICAL testUserRights ():
    // Do some sophisticated right checks
    RETURN TRUE.
  END.

END CLASS. 

SoapService.cls – Service class: This class handles the SOAP protocol level. It has no idea of security (user rights and https).

CLASS 07_Proxy.soapService IMPLEMENTS 07_Proxy.iSoapService: 

  define interface properties

  DEFINE PUBLIC PROPERTY lUseHttps       AS LOGICAL   NO-UNDO GET. SET.
  

  // Connect target URL
  METHOD PUBLIC LOGICAL connectURL ( ).
    /* Use best method to connect remote SOAP URL... */
    RETURN TRUE.
  END METHOD.

  // other functionality here... send, receive, decode...

END CLASS.

start.ptest program: Quite simple test program to start the proxy and initiate a call.

 DEFINE VARIABLE oMySoapService  AS proxySoapService NO-UNDO.

 oMySoapService = NEW proxySoapService().
  
 oMySoapService:cURL = "https://my.service.com".
 oMySoapService:connectURL().
  
 MESSAGE oMySoapService:cConnectResult 
   VIEW-AS ALERT-BOX INFORMATION.

Proxy – Advantages

      • Add control and security
      • Avoid duplication of 'huge' objects and manage their life cycle
      • Allow handling of remote objects

 

Proxy – Disadvantages

      • Additional complexity
      • RMI calls are expensive/slow

 

Conclusion:

Most of the numerous use cases for the proxy pattern can be used with the OpenEdge OO ABL. The OO ABL has no direct RMI capabilities build in. As a workaround use AppServer calls.

OO DESIGN PATTERN IN OO ABL – CONCLUSION

The language of the OpenEdge platform (called ABL or 4GL) is a fully fledged OO programming language today.

Pattern are helpful concepts to organize common scenarios in a project. When used in the same style in a project they become part of the 'documentation', because they make things standardized.

 

Some general points:

      • Pattern are useful for organisation, documentation and maintenance
      • For small projects pattern do not help really
      • Some patterns are similar to others
      • The team should choose a set of patterns for a project
      • Be careful, a pattern could mutate to an anti-pattern
        (e.g. use Singleton for state transfer between objects)
      • Using a pattern just for using a pattern is more worse then never use them.

Some OO ABL specific points

      • More or less all patterns will technically work
      • OO speed in ABL is lower than in other languages, so create large swarms of objects may be slower than expected
        (Progress is working on this)

 

A design pattern is a defined way to solve a problem. Not more and not less. They are a way to keep a project on the road and to give the team a common idea of solutions. If something has a name, you can talk about it.

 

If you are programming OO ABL, find your design pattern and get started implementing it!

Further Reading:

 

Download articles and source codes!

Lets see our three-part series in a single file and download our Code Samples.

Klaus Erichsen
Hamburg, May 2019

Contact me:

Sample source code for the pattern will be released the next days, together with a PDF containing all three articles.

 

Any code is given as example and "as is". Usage is allowed, but IAP is not responsible for the outcome.