© James E. McDonough 2017

James E. McDonough, Object-Oriented Design with ABAP, 10.1007/978-1-4842-2838-8_24

24. Flyweight Design Pattern

James E. McDonough

(1)Pennington, New Jersey, USA

The next stop on our voyage through the Design Patterns galaxy takes us to the Flyweight design pattern , another of the design patterns found in the GoF catalog. We will find this design pattern useful in optimizing components.

Imagine you live in Procedureton and work in Objectropolis, with about 20 kilometers distance separating the two towns. Now imagine your commute between work and home is facilitated by a roadway with a lane dedicated exclusively to your use; no other commuters can use your lane. This would be a boon to those of us who have ever dealt with delays due to heavy traffic or anxiety due to aggressive commuting behaviors. We could arrive and leave work at any time we choose without regard to the commuting habits of others. No longer would we suffer the stress of a tailgating commuter encroaching upon us from behind and creating a dangerous situation.

Now imagine all the residents of Procedureton also work in Objectropolis, and each one of them also has their own dedicated lane of roadway for their exclusive use. The benefits of such an arrangement would be many, but unfortunately this is completely impractical. Aside from the cost to build such a roadway, which would be prohibitive, it would also allocate all the land between the two towns for the sole purpose of surface transportation between them.

In the real world, we are more pragmatic with such matters. We avoid the exorbitant cost and wasteful use of land resources toward building and maintaining such a utopian arrangement by sharing, with all other commuters, a single roadway with perhaps only one lane dedicated for travel in each direction, and, as a consequence, enduring some inconvenience once in a while.

This same concept applies to programming. Some objects require the use of other objects to perform services. Though conceivable for one object to “own” another object, thus restricting it to servicing only the needs of the owning object, we can reap the benefits of improved performance and reduced resource consumption by having fewer of these service objects shared amongst all the objects requiring their services.

Sharing Resources

The Flyweight design pattern reduces the number of objects required for processing by arranging for many objects to share some of the other objects they require instead of each one having its own objects.

The Flyweight design pattern is categorized by GoF with a structural purpose and an object scope. The intent behind this design pattern is the following:

  • Use sharing to support large numbers of fine-grained objects efficiently. 1

The definitive word of the intent is sharing. In order to facilitate sharing, a shared object needs to be designed in such a way that eliminates any attribute values that would prevent it from being used by more than one other object. Attribute values that can be shared become known as intrinsic data and can reside in the shared object because the value is relevant to all sharing objects. Those values that cannot be shared constitute extrinsic data and must be passed to the shared object by each sharing object with each call for services.

Flyweight makes use of these participants2 working in collaboration with each other:

  1. Flyweight: Declares an interface through which flyweights can receive and act on extrinsic state.

  2. ConcreteFlyweight: Implements the Flyweight interface and adds storage for intrinsic state, if any. A ConcreteFlyweight object must be shareable. Any state it stores must be intrinsic; that is, it must be independent of the ConcreteFlyweight object's context.

  3. UnsharedConcreteFlyweight: Not all Flyweight subclasses need to be shared. The Flyweight interface enables sharing; it doesn't enforce it. It's common for UnsharedConcreteFlyweight objects to have ConcreteFlyweight objects as children at some level in the flyweight object structure.

  4. FlyweightFactory: Creates and manages flyweight objects. Ensures that flyweights are shared properly. When a client requests a flyweight, the FlyweightFactory object supplies an existing instance or creates one, if none exists.

  5. Client: Maintains a reference to flyweight(s) . Computes or stores the extrinsic state of flyweight(s).

The UML class diagram for the Flyweight design pattern is shown in Figure 24-1.

A447555_1_En_24_Fig1_HTML.jpg
Figure 24-1. UML class diagram for the Flyweight design pattern

Notice that the FlyweightFactory participant retains a pool of instances of ConcreteFlyweight and UnsharedConcreteFlyweight participants, each of which uses the interface provided by the Flyweight participant. The implementation for its getFlyweight method will determine whether or not an instance of a flyweight by the requested key value already exists, and if one does not exist, will create a new flyweight instance using that key value and add it to the flyweight pool , returning to the caller the new or existing flyweight instance.

Notice also that the ConcreteFlyweight participants retain attributes representing intrinsic state, representing information that can be shared amongst all its users, but that it accepts extrinsic state information through the method signature of the public operation method, requiring all users to provide any information that cannot be shared by all its users.

The UML class diagram for the Flyweight design pattern describing the practical means by which to find the best route for commuting between Procedureton and Objectropolis is shown in Figure 24-2.

A447555_1_En_24_Fig2_HTML.jpg
Figure 24-2. UML class diagram for the Flyweight design pattern applied to a best route scenario

Although we may have many buses simultaneously moving passengers between Procedureton and Objectropolis, each bus does not require its own unique bestRouteIdentifier object. We need a maximum of only two instances of the bestRouteIdentifier class, which could be shared by all of the buses: one describing the best route to Procedureton and the other describing the best route to Objectropolis.

Flyweight in ABAP

Here is how we might implement the Flyweight design pattern UML class diagram illustrated in Figure 24-2 into functioning ABAP code. First, shown in Listing 24-1, is the definition of the vehicle class. We do not show the full definition and implementation of this class since that level of information is not pertinent to the operation of the Flyweight pattern, instead merely indicating that its definition would precede the definition of other classes that will reference it.

Listing 24-1. Class vehicle
class vehicle definition.
  o
  o
endclass.

Listing 24-2 shows the abstract class best_route_identifier, playing the role of the Flyweight participant and defining an abstract method follow_route and accepting an instance of vehicle to follow the route.

Listing 24-2. Abstract class best_route_identifier
class best_route_identifier definition abstract.
  public section.
    methods      : follow_route abstract
                     importing route_follower type ref to vehicle.
endclass.

Notice the absence of any attributes that would prevent instances of this class from being shared amongst multiple vehicles.

Listing 24-3 shows two subclasses, best_route_to_procedureton and best_route_to_objectropolis, inheriting from class best_route_identifier, each playing the role of the ConcreteFlyweight participant. Each one provides an implementation for the abstract follow_route method, inherited from the superclass, providing the best route to its respective destination.

Listing 24-3. Subclasses Inheriting from best_route_identifier
class best_route_to_procedureton definition
                                 inheriting from best_route_identifier.
  public section.
    methods      : follow_route redefinition.
endclass.
class best_route_to_procedureton implementation.
  method follow_route.
    statements go here indicating best route to Procedureton
  endmethod.
endclass.


class best_route_to_objectropolis definition
                                inhering from best_route_identifier.
  public section.
    methods      : follow_route redefinition.
endclass.
class best_route_to_objectropolis implementation.
  method follow_route.
    statements go here indicating best route to Objectropolis
  endmethod.
endclass.

Listing 24-4 shows the static route_identifier_factory class with its public static method get_best_route. This class plays the role of the FlyweightFactory participant. Notice that its implementation of this public method searches for an existing entry in the best_route_identifier_pool, and if one is not found for the desired destination, an object of type best_route_identifier is created and is used to populate a new entry in the best_route_identifier_pool.

Listing 24-4. Static Class best_route_identifier_factory
class best_route_identifier_factory definition abstract final.
  public section.
    class-methods: get_best_route
                     importing desired_destination
                       type string
                     exporting best_route
                       type ref to best_route_identifier.
  private section.
    types        : begin of route_identifier_entry
                 ,   destination  type string
                 ,   best_route   type ref to best_route_identifier
                 , end   of route_identifier_entry
                 .
    class-data   : best_route_identifier_pool
                     type standard table of route_identifier_entry.


    class-methods: create_best_route_instance
                     importing destination
                       type string
                     exporting best_route
                       type ref to best_route_identifier.
endclass.
class best_route_identifier_factory definition.
  method get_best_route.
    data         : route_identifier
                     like line of best_route_identifier_pool.
    read table best_route_identifier_pool
          into route_identifier
          with key destination = desired_destination.
    if route_identifier-destination is initial.
      route_identifier-destination = desired_destination.
      call method create_best_route_instance
        exporting destination = desired_destination
        importing best_route  = route_identifier-best_route.
      append route_identifier
          to best_route_identifier_pool.
    endif.
    best_route = route_identifier-best_route.
  endmethod.
  method create_best_route_instance.
    statements go here to create new instance of best_route_identifier
      subclass to facilitate travel to the specified destination
  endmethod.
endclass.

Notice the definition of the pool of flyweights holding various instances of best_route_identifiers, each one accompanied by the destination for which the flyweight instance represents the best route. This means that vehicle instances that would make a request to best_route_identifier_factory to get the best route to its destination will all share the same set of best_route_identifiers; none of them are associated with any specific vehicle instance.

Listing 24-5 shows the definition of the bus class , playing the role of the Client participant, using the best_route_identifier_factory.

Listing 24-5. Class bus
class bus definition inheriting from vehicle.
  public section.
    methods      : move_passengers.
  private_section
    methods      : load_passengers.
endclass.
class bus implementation.
  method move_passengers.
    data         : fastest_path type ref to best_route_identifier.
    call method me->load_passengers.
    call method best_route_identifier_factory=>get_best_route
      exporting desired_destination = 'Objectropolis'.
      importing best_route          = fastest_path.
    call method fastest_path->follow_route( me ).
  endmethod.
  method load_passengers.
    statements go here indicating how to load passengers
  endmethod.
endclass.

Notice that method move_passengers of the bus class invokes method get_best_route of static class best_route_identifier_factory, passing the name of the destination and receiving an instance of best_route_identifier holding the best path to that destination. It then invokes method follow_route of the instance best_route_identifier, passing itself via the me current instance reference to the bus. Any vehicle instances that call method get_best_route of class best_route_identifier_factory using the same destination will receive a reference to the very same instance of best_route_identifier as all other vehicle instances making this call.

Summary

In this chapter, we learned about intrinsic and extrinsic information, and that we can reduce the number of objects required in a design if we can create classes that retain only intrinsic information, leaving it to users of the class to provide whatever extrinsic information might be necessary. This pattern provides us with another way in which we can share objects among many users, utilize resources more efficiently, reduce storage consumption, and optimize the performance of the components we require.

Flyweight Exercises

Refer to Chapter 21 of the functional and technical requirements documentation (see Appendix B) for the accompanying ABAP exercise programs associated with this chapter. Take a break from reading the book at this point to reinforce what you have read by changing and executing the corresponding exercise programs. The exercise programs associated with this chapter are those in the 314 series: ZOOT314A through ZOOT314C.

Footnotes

1 GoF, p. 195.

2 GoF, p. 198.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset