13 May 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'.
PATTERN 6 – FACTORY/FABRIC (CREATIONAL PATTERN)
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
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.p – test 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 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
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.p – test 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!
Download articles and source codes!
Lets see our three-part series in a single file and download our Code Samples.