Thursday, September 3, 2009

Patterns - 020: Collectional patterns ( Flyweight )


Every object can be viewed as consisting of one or both of the following two sets of information:

  1. Intrinsic Information — The intrinsic information of an object is independent of the object context. That means the intrinsic information is the common information that remains constant among different instances of a given class. For example, the company information on a visiting card is the same for all employees.
  2. Extrinsic Information — The extrinsic information of an object is dependent upon and varies with the object context. That means the extrinsic information is unique for every instance of a given class. For example, the employee name and title are extrinsic on a visiting card as this information is unique for every employee.

The Flyweight pattern suggests separating all the intrinsic common data into a separate object referred to as a Flyweight object. The group of objects being created can share the Flyweight object as it represents their intrinsic state. This eliminates the need for storing the same invariant, intrinsic information in every object; instead it is stored only once in the form of a single Flyweight object. As a result, the client application can realize considerable savings in terms of the memory-usage and the time.

When the Flyweight pattern is applied, it is important to make sure that the requirements listed in follow :

  1. There exists only one object of a given flyweight kind and is shared by all the other appropriate objects.
  2. Client objects should not be allowed to create flyweight instances directly. At the same time, client objects should have a way of accessing a required Flyweight object when needed.

One of the ways to design a flyweight in Java is to design it as a singleton similar to the Flyweight class.






As an alternate design strategy, the responsibility of creating and maintaining different singleton Flyweight objects can be moved out of the Flyweight to a designated FlyweightFactory. The Flyweight can be designed as an inner class of the FlyweightFactory class. Since the Flyweight class is defined with a private constructor, external objects are prevented from creating its instances by directly invoking the constructor. But the FlyweightFactory can invoke the Flyweight class private constructor to create necessary Flyweight objects. This is because an outer class can access the private methods of its inner class.








Example

let us design an application that prints out the data for visiting cards of all the employees of a large organization with four major divisional offices. A typical visiting card can be assumed to have the following layout:

  • name of the Employee
  • title of the Employee
  • company name
  • office address
  • office city
  • office state
  • office zip

  • The name and the title are unique for every employee and can be considered as the extrinsic data.
  • The company name remains the same for all employees and every employee working under a divisional office is given the same divisional office address. Therefore the company name and division address part of a visiting card can be treated as the intrinsic data.

Design approach 1




Overall Design






          FlyweightIntr Intrface

              public interface FlyweightIntr {
              public String getCompany();
              public String getAddress();
              public String getCity();
              public String getState();
              public String getZip();
              }

          Singleton FlyweightFactory Class with Inner Flyweight Class
        
              import java.util.*;

              public class FlyweightFactory {
                  private HashMap lstFlyweight;
                  private static FlyweightFactory factory =
                          new FlyweightFactory();

                  private FlyweightFactory() {
                      lstFlyweight = new HashMap();
                  }

                  public synchronized FlyweightIntr getFlyweight(
                          String divisionName) {
                      if (lstFlyweight.get(divisionName) == null) {
                          FlyweightIntr fw = new Flyweight(divisionName);
                          lstFlyweight.put(divisionName, fw);
                          return fw;
                      } else {
                          return (FlyweightIntr) lstFlyweight.get(divisionName);
                      }
                  }

                  public static FlyweightFactory getInstance() {
                      return factory;
                  }

                  //Inner flyweight class
                  private class Flyweight implements FlyweightIntr {
                      private String company;
                      private String address;
                      private String city;
                      private String state;
                      private String zip;

                      private void setValues(String cmp, String addr,
                                             String cty, String st, String zp) {

                          company = cmp;
                          address = addr;
                          city = cty;
                          state = st;
                          zip = zp;

                      }

                      private Flyweight(String division) {
                          // values are hard coded
                          //for simplicity
                          if (division.equals("North")) {
                              setValues("CMP", "addr1", "cty1", "st1", "10000");
                          }
                          if (division.equals("South")) {
                              setValues("CMP", "addr2", "cty2", "st2", "20000");
                          }
                          if (division.equals("East")) {
                              setValues("CMP", "addr3", "cty3", "st3", "30000");
                          }
                          if (division.equals("West")) {
                              setValues("CMP", "addr4", "cty4", "st4", "40000");
                          }
                      }

                      public String getCompany() {
                          return company;
                      }

                      public String getAddress() {
                          return address;
                      }

                      public String getCity() {
                          return city;
                      }

                      public String getState() {
                          return state;
                      }

                      public String getZip() {
                          return zip;
                      }

                  }
              }

          VCard Class Using a Flyweight Object to Represent the Intrinsic Data
        
              public class VCard {

                  String name;
                  String title;
                  FlyweightIntr objFW;

                  public VCard(String n, String t, FlyweightIntr fw) {
                      name = n;
                      title = t;
                      objFW = fw;
                  }

                  public void print() {
                      System.out.println(name);
                      System.out.println(title);
                      System.out.println(objFW.getAddress() + "-" +
                              objFW.getCity() + "-" +
                              objFW.getState() + "-" +
                              objFW.getZip());
                      System.out.println("----------------");
                  }
              }

Design approach 2

Extrinsic data passed to the flyweight as part of a method call and was not represented as an object







  • The print method:
  1. – Needs to be moved from the VCard class to the Flyweight class.
  2. – Should be implemented to display the extrinsic data passed to it alongwith the intrinsic data it represents.
  3. – Signature needs to be changed from
public void print()
to
public void print(String name, String title)

in order to accept the extrinsic data as arguments.



No comments:

Post a Comment