Your Federal Quarterly Tax Payments are due April 15th Get Help Now >>

Section 3 by gegeshandong

VIEWS: 8 PAGES: 69

									Section 3


Payroll Case Study
The Payroll System – Initial Requirement


                             correct amount
 Employee                    (minus deductions)
 Database   Payroll System
                              on time

                             method specified
    Payroll Initial Spec
   Pay Type:
      Hourly. Some employees work by the hour. Paid hourly rate. Submit
       time cards. Paid overtime @ 1.5 times rate. Paid every Friday.
      Salary. Some employees salaried. Paid last working day of month.
      Commission. Some employees also paid commission based on
       sales. Submit sales amounts. Paid every Friday.
      Commission rate, salary, hourly rate are part of employee record.
   Pay Method.
      Employees can choose for paychecks to be mailed, held for pickup,
       or directly deposited to bank account.
   Deductions.
      Some employees belong to the union. Employee record has field for
       weekly dues rate. Must be deducted from pay. Union may assess
       service charges from time to time. These are submitted by union
       on weekly basis and must be deducted from appropriate
       employee’s next pay amount.
   Other requirements.
      Payroll application will run once each working day and pay the
       appropriate employees on that day. The system will be told to
       what date the employees are to be paid, so it will calculate
       payments from the last time the employee was paid up to the
       specified date.
Chapter 18


Payroll Case Study
How to begin?
Obviously a database is involved. Should we generate
  a database schema and some queries?

   Common – but this generates an application for
    which the database is the central concern.
   Databases are implementation details!
   Considering the database should be deferred as
    long as possible.
   Abstraction: the amplification of the essential and
    the elimination of the irrelevant. The database is
    irrelevant at this stage; it is merely a technique
    used for storing and accessing data, nothing more.
Analysis by Use Cases
    Start by considering the behavior of the system.
    Use case: similar to a story, but elaborated with
     more detail
    Stories for this iteration:
    1. Add a new employee
    2. Delete an employee
    3. Post a time card
    4. Post a sales receipt
    5. Post a union service charge
    6. Change employee details (e.g., hourly rate,
        dues rate)
    7. Run the payroll for today
Use Case 1: Add New Employee
A new employee is added by the receipt of an AddEmp transaction.
   This transaction contains the employee’s name, address, and
   assigned employee number. The transaction has 3 forms:

AddEmp <EmpId> “<name>” “<address>” H <hourly-rate>
AddEmp <EmpId> “<name>” “<address>” S <monthly-salary>
AddEmp <EmpId> “<name>” “<address>” C <monthly-salary> <comm-rate>

The employee record is created with fields assigned appropriately.

Alternative 1:
An error in the transaction structure.

If the transaction structure is inappropriate, it is printed out in an
    error message and no action is taken.
Thinking about the design…
   Use case 1 hints at an abstraction:
                          AddEmployee
                          Transaction          We’ll look at the COMMAND
                          - Name               pattern for this abstract base
                          - EmployeeId         class…
                          - Address



          AddHourly        AddSalaried       AddCommissioned
           Employee         Employee             Employee
          Transaction      Transaction          Transaction


SRP adhered to: each responsibility in its own class

                                         Don’t get sucked into the database yet!!
OK to think about objects…


                    Employee



       Hourly        Salaried        Commissioned
      Employee      Employee           Employee



             Possible Employee class hierarchy
Use Case 2: Delete an Employee
Employees are deleted when a DelEmp transaction is received.
  The form of this transaction is as follows:
DelEmp <EmpId>

When this transaction is received, the appropriate employee
   record is deleted.
Alternative 1:
Invalid or unknown EmpID

If the <EmpID> field is not structured correctly, or it does not
    refer to a valid employee record, then the transaction is
    printed with an error message and no other action is taken.


No design insights from this use case, so let’s move on…
Use Case 3: Post Time Card
On receiving a TimeCard transaction, the system will create a
  time-card record and associate it with the appropriate
  employee record.
TimeCard <EmpId> <date> <hours>

Alternative 1:
The selected employee is not hourly
The system will print an appropriate error message and take no
   further action

Alternative 2:
An error in the transaction structure
The system will print an appropriate error message and take no
   further action
Design insights…
 Some transactions apply only to
  certain kinds of employees –
  strengthen case for different classes.
 Indicates association between time
  cards and hourly employees.

         Hourly            0..*
                                  TimeCard
        Employee

                   remember aggregation?
                   Could also be composition, if TimeCard objects
                   are destroyed when Employee is destroyed
Use Case 4: Posting a Sales Receipt
Upon receiving the SalesReceipt transaction, the system will
  create a new sales-receipt record and associate it with the
  appropriate commissioned employee.
SalesReceipt <EmpId> <date> <amount>
Alternative 1:
The selected employee is not commissioned.
The system will print an appropriate error message and take no
   further action.

Alternative 2:
An error in the transaction structure.
The system will print an appropriate error message and take no
   further action.
Design insights…
   This is very similar to use case 3. It
    implies the following structure:


       Commissioned    0..*
                              Sales Receipt
         Employee
Use Case 5: Post Union Service Charge
Upon receiving this transaction, the system will create
  a service-charge record and associate it with the
  appropriate union member.
ServiceCharge <memberID> <amount>
Alternative 1:
Poorly formed transaction
If the transaction is not well formed or if the <memberID>
    does not refer to an existing union member, then the
    transaction is printed with an appropriate error message.
Design Insights…
   Union members are not accessed through
    employee IDs. The union maintains its own
    numbering scheme. The system must be able to
    associate union members and employees. Could
    be done various ways, so postpone decision until
    later. Just show association for now.           Example of how
                                                    this differs from
                                                    waterfall…


                             0..*
         UnionMember                ServiceCharge
Use Case 6: Change Employee Details
Upon receiving this transaction the system will alter one of the details of the
   appropriate employee record. Several possible variations:
ChgEmp   <EmpID>   Name <name>
ChgEmp   <EmpID>   Address <address>
ChgEmp   <EmpID>   Hourly <hourlyRate> // Change to hourly
ChgEmp   <EmpID>   Salaried <salary> // Change to salary
ChgEmp   <EmpID>   Commissioned <salary> <rate>
ChgEmp   <EmpID>   Hold
ChgEmp   <EmpID>   Direct <bank> <account>
ChgEmp   <EmpID>   Mail <address>
ChgEmp   <EmpID>   Member <memberID> Dues <rate>
ChgEmp   <EmpID>   NoMember


Alternative 1:
An error in the transaction structure.

If the transaction structure is inappropriate, or <EmpID> does not refer to a real
     employee, or <memberID> already refers to a member, then print a suitable
     error and take no further action
Design insights…
 Use case has shown all aspects of
  employee that are changeable.
 Note that employees can change from
  hourly to salaried and vice versa.
  Initial class design may not be
  appropriate. Use STRATEGY pattern
  instead (see class diagram next slide)
 Use the NULL OBJECT pattern for union
  membership.
 Updated class design
          <<interface>>           Employee             <<interface>>
            Payment                                      Affiliation
             Method
                                   Payment                                NoAffiliation**
                                 Classification*
HoldMethod
                                                                          UnionAffiliation
MailMethod                                                                - Dues
                                  Salaried
- Address                         Classification                                    0..*
                                  - Salary                                ServiceCharge
DirectMethod
- Bank           Hourly                            Commissioned
- Account        Classification                    Classification
                 - HourlyRate                      - CommissionRate
                                                   - Salary
                          0..*

                 TimeCard                                  0..*        *strategy class
                                                    SalesReceipt       ** NULL object pattern
Use Case 7: Run Payroll for Today
Upon receiving the Payday transaction, the system
  finds all those employees that should be paid on
  the specified date. The system then determines
  how much they are owed and pays them according
  to their selected payment method.
Payday <date>
Finding Abstractions
   Must hunt for abstractions, because often
    not stated or even alluded to by application
    requirements.
   Example:
     Some   employees work by the hour
     Some   employees are paid a flat salary
     Some   employees are paid a commission
   Generalization: All employees are paid, but
    they are paid by different schemes.
   Abstraction: All employees are paid. Lead
    to PaymentClassification.
Another abstraction
   Scheduling the payroll:
       They are paid every Friday
       They are paid on last working day of month
       They are paid every other Friday
   Generality: All employees are paid according to
    some schedule.
   Abstraction: schedule.
   Use cases link schedule to payment classification.
    BUT, it seems possible that this could change (e.g.,
    employees in different departments might be paid
    on different days). Also, if linked then a change in
    payment classification would require testing the
    schedule as well.
   Schedule abstraction not included in original design
Chapter 13


COMMAND and
ACTIVE OBJECT
COMMAND: simple + elegant

     <<interface>>            public interface Command
     Command                  {
     + do()                     public void do();
                              }




  Elevates the role of a function to the level of a class. Blasphemy!
  But interesting designs can unfold…
Simple Commands
                                              do()
                <<interface>>
                Command
                + do()


                                                              do()
 RelayOn       MotorOn          ClutchOn              init
Command        Command          Command               ClutchOnCommand
                                                      MotorOnCommand
       RelayOff       MotorOff         ClutchOff
      Command         Command          Command

Embedded real-time software for a photocopier. Pass Command() objects around
system and call do() without knowing which type of Command they represent.
(next slide…)
Copier example, continued


           Sensor                   Command




Example: sensor needs to engage clutch at point in paper path. Bind
appropriate ClutchOnCommand to object.

Sensor detects event, calls do().

Complexity of determining which relays to connect to which sensors is now
handled by an initialization function.
Transactions: a type of do()
   Maintain database of employees. Number of operations that users can
    apply (add, delete, modify).
   Command object collects unvalidated data, implements validation
    methods, executes transactions.

                       Employee                         <<interface>>
                       - name                           Transaction
                       - address                        + validate()
                                                        + execute()
                   <<interface>>
                   PayClassification
                   + CalculatePay()                     AddEmployee
                                                                        <<interface>>
                                                        Transaction
                                                                        Pay
Commissioned       Salaried            Hourly           - name          Classification
Classification     Classification      Classification   - address       + CalculatePay()
- basePay          - monthlyPay        - hourlyRate     + validate()
- commissionRate                                        + execute()
       0..*                                  0..*
 SalesReceipt                           TimeCard
 - date                                 - date
 - amount                               - amount
Command Benefits
   Physical and Temporal Decoupling
      Decouple code that procures data from user (probably a
       dialog in some GUI) from code that validates and from
       business objects. If coupled, validation code couldn’t be
       used other places. Code that manipulates database
       should also be separate.
      Temporal decoupling. Transaction data can be collected
       and processed later. For example, maybe changes to
       database should only occur in the evening.
   Undo
       Easy to add an undo() method to the COMMAND pattern.
        Can reverse the effects of a do().
ACTIVE OBJECT
 Old technique for implementing
  multiple threads of control.
 Not covered – threads covered in OS
  and PL
Chapter 14

TEMPLATE METHOD &
STRATEGY
Inheritance vs. Delegation
Inheritance
   Brave new world in early 90s
   Could program by difference – find class
    that did something almost useful to us,
    create subclass and change only what didn’t
    work in new domain
   BUT, easy to overuse inheritance
   New advice: “Favor object composition over
    class inheritance”
   Need to carefully consider, use inheritance,
    composition and delegation appropriately
TEMPLATE METHOD - inheritance
Common main-loop structure:
Initialize();
while (!done()) // main loop
{
  Idle(); // do something useful
}
Cleanup();

Use the pattern to create abstract base classes that
  can work on various types of objects.
  Example: Bubble Sorter
       First, we have a sort that knows how to work with
        integers:
public class BubbleSorter                     private static void swap
{                                               (int[] array, int index)
  static int operations = 0;                    {
  public static int sort(int [] array)            int temp = array[index];
  {                                               array[index] = array[index+1];
    operations = 0;                               array[index+1] = temp;
    if (array.length <= 1)                      }
      return operations;
                                              private static void compareAndSwap
      for (int nextToLast = array.length-2;     (int[] array, int index)
           nextToLast >= 0; nextToLast--)       {
        for (int index = 0;                       if (array[index]> array[index+1])
             index <= nextToLast; index++)          swap(array, index);
          compareAndSwap(array, index);           operations++;
                                                }
      return operations;                      }
  }
  Bubble Sorter, continued
      Can create abstract class instead:
public abstract class BubbleSorter         protected abstract void swap(int index);
{                                          protected abstract boolean outOfOrder
  private int operations = 0;                (int index);
  protected int length = 0;                }

  protected int doSort()    {
    operations = 0;                                  BubbleSorter
    if (length <= 1)                                 {abstract}
      return operations;                             # outOfOrder
      for (int nextToLast = length-2;
                                                     # swap
           nextToLast >= 0;
           nextToLast--)
        for (int index = 0;
           index <= nextToLast; index++)
        {                                   IntBubble           DoubleBubble
          if (outOfOrder(index))              Sorter               Sorter
            swap(index);
          operations++;
        }
      return operations;
  }
   Bubble Sorter, continued
      Implement methods for Int and Double:
public class IntBubbleSorter            public class DoubleBubbleSorter
   extends BubbleSorter                     extends BubbleSorter
{                                       {
 private int[] array = null;             private double[] array = null;
 public int sort(int [] theArray)        public int sort(double [] theArray)
 {                                       {
   array = theArray;                       array = theArray;
   length = array.length;                  length = array.length;
   return doSort();                        return doSort();
 }                                       }
 protected void swap(int index)          protected void swap(int index)
 {                                       {
   int temp = array[index];                double temp = array[index];
   array[index] = array[index+1];          array[index] = array[index+1];
   array[index+1] = temp;                  array[index+1] = temp;
 }                                       }
 protected boolean outOfOrder             protected boolean outOfOrder
   (int idx)                                 (int idx)
 {                                        {
   return (array[idx]> array[idx+1]);       return (array[idx]> array[idx+1]);
 }                                        }
}                                       }
STRATEGY pattern
   Another way to solve the problem of inverting the
    dependencies
   Instead of putting generic application algorithm in an abstract
    class, place it in a concrete class named ApplicationRunner
   Abstract methods that must be called are defined in the
    Application interface
   ftocStrategy is derived from this interface. An object of this
    class can be passed to ApplicationRunner
                       <<interface>>                 ftoc = fahrenheit to celcius
         Application   Application
         Runner        + init
         + run         + idle
concrete class         + cleanup
                       + done: boolean


                        ftocStrategy
                                         concrete class
Strategy code
public class ApplicationRunner
{
  private Application itsApplication = null;
                                          can pass in ftocStrategy, etc.
  public ApplicationRunner(Application app)
  {
    itsApplication = app;
  }
  public void run()
  {
    itsApplication.init();
    while (!itsApplication.done())
      itsApplication.idle();      public interface Application
    itsApplication.cleanup();     {
  }                                 public void init();
}                                   public void idle();
                  calls methods
                  from interface    public void cleanup();
                                    public boolean done();
                                  }
Strategy code, continued

   import java.io.*;
   public class ftocStrategy implements Application
   {
     private InputStreamReader isr;
     private BufferedReader br;
     private boolean isDone = false;

     public static void main(String[] args) throws Exception
     {
       (new ApplicationRunner(new ftocStrategy())).run();
     }

     public void init()
     {
       isr = new InputStreamReader(System.in);
       br = new BufferedReader(isr);
     }

   // More code in textbook
Strategy pros and cons
   Strategy involves more classes
   Delegation pointer in ApplicationRunner
    incurs some overhead

BUT

   Easy to reuse ApplicationRunner by passing
    in different implementations of Application
 Another example – sorting again
public class BubbleSorter
{
  private int operations = 0;
  private int length = 0;
  private SortHandle itsSortHandle = null;
  public BubbleSorter(SortHandle handle) {
                                               public interface SortHandle
    itsSortHandle = handle;
                                               {
  }
                                                 public void swap(int index);
public int sort(Object array) {
                                                 public boolean outOfOrder(int index);
    itsSortHandle.setArray(array);
                                                 public int length();
    length = itsSortHandle.length();
                                                 public void setArray(Object array);
    operations = 0;
                                               }
    if (length <= 1)
      return operations;

    for (int nextToLast = length-2;
            nextToLast >= 0; nextToLast--)
      for (int index = 0;
               index <= nextToLast; index++)
      {
        if (itsSortHandle.outOfOrder(index))
          itsSortHandle.swap(index);
        operations++;
      }
    return operations;
  }}
Sorting continued
public class IntSortHandle implements SortHandle
{
  private int[] array = null;
                                                Notice:
    public void swap(int index) {               • IntSortHandle knows nothing of
      int temp = array[index];                    BubbleSorter
      array[index] = array[index+1];            • IntSortHandle could therefore be
      array[index+1] = temp;
    }                                             used with other sorts – e.g.,
                                                  QuickBubbleSorter that stops
    public void setArray(Object array) {          when the array is in order (code
      this.array = (int[])array;
                                                  in text)
    }
                                                • Strategy allows the details to be
    public int length() {                         reused independently of the
      return array.length;                        high-level algorithm!
    }
                                                               More comparison sorts
    public boolean outOfOrder(int index) {                     covered in CSCI406
      return (array[index] > array[index+1]);
    }
}
Chapter 15


FAÇADE and
MEDIATOR
Policy patterns
 Both Façade and Mediator impose
  some kind of policy on another group
  of objects
 Façade imposes policy from above
 Mediator imposes policy from below
 Façade is visible and constraining
 Mediator is invisible and enabling
  Facade
     Used to provide a simple, specific interface for a group of
      objects that has a complex, general interface
                                  Product-specific sql interface; complex but
public class DB {
  private static Connection con;
                                  shields users from knowing sql details
  public static void init() throws Exception {…}
  public static void store(ProductData pd) throws Exception {…} // Products
  private static PreparedStatement buildProductInsertionStatement
       ProductData pd) throws SQLException
  public static ProductData getProductData(String sku) throws Exception
  private static PreparedStatement buildProductQueryStatement(String sku)
  private static ProductData extractProductDataFromResultSet(ResultSet rs)
  public static void store(ItemData id) throws Exception {…} // Items
  private static PreparedStatement buildItemInsersionStatement(ItemData id)
  public static ItemData[] getItemsForOrder(int orderId) throws Exception
  private static PreparedStatement buildItemsForOrderQueryStatement
    (int orderId) throws SQLException
  private static ItemData[] extractItemDataFromResultSet(ResultSet rs)
  public static OrderData newOrder(String customerId) throws Exception
  private static int getMaxOrderId() throws SQLException // Orders
  public static OrderData getOrderData(int orderId) throws SQLException
  private static void executeStatement(PreparedStatement s)
  public static void close() throws Exception {…}
  public static void clear() throws Exception {…}
 }
 DB Facade
                              DB
        ProductData           + store(ProductData)               Application
                              + getProductData(sku)
                              + deleteProductData(sku)
                              …
       java.sql

        Connection       Statement         DriverManager


        ResultSet         Prepared         SQLException
                          Statement


All database calls must go through DB. Direct calls to java.sql violate convention.

Policy is visible – application sees interface it provides. Valid operations are all
provided. Simplifies – application programmers don’t all need to learn sql
interface, just use DB.
Mediator
   Imposes policy in hidden, constrained way.
    QuickEntryMediator selects the first entry in a list
    that matches the current prefix in a JTextField.
                                                     State
JList                  JTextField                        CO        ALABAMA
                                                                   ALASKA
                                                                   ARIZONA
                                                                   ARKANSAS
                                <<anonymous>>                      CALIFORNIA
           QuickEnty                                               COLORADO
                                   Document
                                                                   CONNECTICUT
           Mediator                 Listener                       DELAWARE




    Hidden: Users of JList and JTextField have no idea that this Mediator exists.
Mediator QuickEntry Example
public class QuickEntryMediator { State      List of states
  public QuickEntryMediator(JTextField t, JList l) {
    itsTextField = t;
    itsList = l;
                                         responds to JTextField events, shown
    itsTextField.getDocument().addDocumentListener(        on next slide
      new DocumentListener() {
        public void changedUpdate(DocumentEvent e) {
          textFieldChanged();
        }

        public void insertUpdate(DocumentEvent e) {
          textFieldChanged();
        }

        public void removeUpdate(DocumentEvent e) {
          textFieldChanged();
        }
      } // new DocumentListener
    ); // addDocumentListener
  } // QuickEntryMediator()
Mediator QuickEntry continued
private void textFieldChanged() {
    String prefix = itsTextField.getText();

    if (prefix.length() == 0) { // clear selection if user clears field
      itsList.clearSelection();
      return;
    }
    ListModel m = itsList.getModel(); // finds first item that matches
    boolean found = false;            // text typed so far
    for (int i = 0; found == false && i < m.getSize(); i++) {
      Object o = m.getElementAt(i);
      String s = o.toString();
      if (s.startsWith(prefix)) {
        itsList.setSelectedValue(o, true);
        found = true; // found is true if any items in list match prefix
      }
    }
    if (!found) { // clear if nothing matches text entry
      itsList.clearSelection();
    }
  } // textFieldChanged
  private JTextField itsTextField;
  private JList itsList;
} // class QuickEntryMediator
Chapter 16


SINGLETON and
MONOSTATE
Sometimes you only need one…
   Normally there is a one-to-many relationship
    between classes and objects
   Some classes should only have one instance
       factories
       managers (e.g., print, other resources)
       root of application
   If more than one, logic errors may occur
   May be able to just create one when application
    starts and be done with it application root
   Sometimes it is important to enforce singularity
   Two patterns to do that: singleton & monostate
SINGLETON pattern
   Simple to implement
   Access through public method, e.g., Instance
   Instance always returns same object
   No public constructors, so can’t create a second
    object of same type
       public class Singleton{
              private static Singleton theInstance = null;
              private Singleton() {}

             public static Singleton Instance()
             {
                    if (theInstance == null)
                           theInstance = new Singleton();
                    return theInstance;
             }
       }
  Testing the SINGLETON
@Test
public void testCreateSingleton()
{
       Singleton s = Singleton.Instance();
       Singleton s2 = Singleton.Instance();
       assertSame(s, s2);
}

@Test (expected=Exception.class)
public void testNoPublicConstructors()
{
       Class singleton = Class.forName("Singleton");
       Constructor[] constructors = singleton.getConstructors();
       assertEquals("Singleton has public constructors.",
              0, constructors.length);
}
Pros and Cons
Benefits of SINGLETON:             Costs of SINGLETON:
 Cross platform. Can extend to     Destruction undefined. If NULL
   work across many JVMs and         out theInstance, other modules
   computers.                        may still hold reference. So??
 Applicable to any class. Just     Not inherited. Class derived
   make constructors private and     from SINGLETON is not a
   add static functions and          SINGLETON. Would need to add
   variable.                         function to subclass.
 Can derive a singleton from       Efficiency. Each call to
   some other class. Given a         Instance invokes an if important?
   class, can create a subclass      statement, most often useless.
   that is a SINGLETON              Nontransparent. Users of
 Lazy evaluation. If SINGLETON      SINGLETON must know they
   is never used, it is never        are using SINGLETON because
   created                           they must invoke Instance
                                     method.
SINGLETON Example                                        No IF statement,
                                                         using Java initialization
  private static UserDatabase theInstance =
      new UserDatabaseSource();

  public static UserDatabase instance() {
      return theInstance;
  }

  private UserDatabaseSource(){}

  public User readUser(String userName){
      // Some Implementation
      return null; // just to make it compile.
  }

  public void writeUser(User user){
      // Some Implementation
  }

Common usage, ensures all database access via single instance of Façade.
Two possible approaches
   MONOSTATE enforces the behavior of
    singularity
   SINGLETON enforces the structure
  MONOSTATE
     Have multiple instances of Monostate, all act as one

import junit.framework.*;
public class TestMonostate extends TestCase
{
  public TestMonostate(String name) {            Two instances of Monostate
     super(name);                                behave as though they were one
  }
                                        public void testInstancesBehaveAsOne() {
  public void testInstance() {            Monostate m1 = new Monostate();
     Monostate m = new Monostate();       Monostate m2 = new Monostate();
     for (int x = 0; x<10; x++) {
          m.setX(x);                      for (int x = 0; x<10; x++) {
          assertEquals(x, m.getX());           m1.setX(x);
     }                                         assertEquals(x, m2.getX());
}                                         }
                                        }
                                      }
MONOSTATE continued
   How can that be?
     Objects      share same variables – because they are
      static
     BUT, none of the methods are static so they are
      accessed via actual instances of class objects
          public class Monostate
          {
              private static int itsX = 0;
              public Monostate() {}

                 public void setX(int x) {
                     itsX = x;
    not static   }
                 public int getX() {
                     return itsX;
                 }
          }
Monostate Turnstile Example
   Turnstile begins in locked state. Returns to locked
    state after people pass.
   If coin is deposited, transition to Unlocked state,
    unlock gate, reset alarm, deposit coins in its bin
   Abnormal condition 1: user deposits two coins
    before passing through. Coins are refunded, gate
    remains unlocked.
   Abnormal condition 2: user passes through without
    paying. Alarm sounds, gate locked.
                                                       Turnstile finite
Pass /             Coin / Unlock, AlarmOff, Deposit    state machine
Alarm     Locked


                                            Unlocked     Coin / Refund
                   Pass / Lock
Turnstile Code
public class Turnstyle
{
          private static boolean isLocked;
          private static boolean isAlarming;
          private static int itsCoins;
          private static int itsRefunds;
          protected final static Turnstyle LOCKED = new Locked();
          protected final static Turnstyle UNLOCKED = new Unlocked();
          protected static Turnstyle itsState = LOCKED;

        public void reset() {
                 lock(true);
                 alarm(false);
                 itsCoins = 0;
                 itsRefunds = 0;
                 itsState = LOCKED;
        }
    Turnstile code, continued
class Locked extends Turnstyle              class Unlocked extends Turnstyle
{                                           {
    public void coin() {                        public void coin() {
        itsState = UNLOCKED;                         refund();
         lock(false);                           }
         alarm(false);
         deposit();                             public void pass() {
    }                                                lock(true);
                                                     itsState = LOCKED;
      public void pass() {                      }
           alarm(true);                     }
      }
}


    The event functions (coin and pass) are delegated to two derivatives of Turnstyle
    (Locked and Unlocked) that represent the states of the finite-state machine.
    Derivatives are automatically MONOSTATE. Since these are all MONOSTATE,
    Locked and Unlocked are not really separate objects, so no violation of OO
    principles.

    NOTE: Controlling more than one turnstile would require significant refactoring.
Turnstile code, continued
   See rest of code + JUnit tests in
    textbook
Benefits of MONOSTATE
   Transparency. Users do not need to know
    that object is MONOSTATE, because usage
    is same as for a regular object
   Derivability. Derivatives of MONOSTATE are
    MONOSTATE – they share the same
    variables
   Polymorphism. Since methods are not
    static, they can be overridden. Different
    behavior, same set of static variables.
   Well-defined creation and destruction.
    Static variables in MONOSTATE have well-
    defined creation and destruction times.
Costs of MONOSTATE
   No conversion. Normal class cannot be
    converted to MONOSTATE through
    derivation.
   Efficiency. May have many creations and
    destructions because MONOSTATE is a real
    object. These are costly operations.
   Presence. Variables of MONOSTATE take up
    space, even if MONOSTATE never used.
   Platform local. You can’t make a
    MONOSTATE work across several JVM
    instances or across several platforms.
Which option to use?
 SINGLETON is best when you have an
  existing class that you want to
  constrain through derivation, and you
  don’t mind requiring users to call
  instance()
 MONOSTATE is best when you want
  singular nature of class to be
  transparent or when you want to
  employ polymorphic derivatives
Chapter 17


NULL OBJECT
Common “null” code technique
 Rely on short-circuit evaluation
 Error-prone (may forget)
         Employee e = DB.getEmployee(“Bob”);
         if (e != null && e.isTimeToPay(today))
           e.pay();




   Try/catch can be even worse
An alternative: NULL OBJECT
   Employee interface has two implementations
   Normal implementation works as usual
   NULL implementation methods do “nothing”

         DB                    <<interface>>
                                 Employee



          <<creates>>
                        NullEmployee           Employee
                                             Implementation
                               <<creates>>

                                                      NullEmployee is returned
    Employee e = DB.getEmployee(“Bob”);
                                                      if “Bob” object doesn’t exist
    if (e.isTimeToPay(today))
      e.pay();
                                                      isTimeToPay will return false
 NULL Object Code
public class DB{
  public static Employee getEmployee(String name){
    return Employee.NULL;
  }
}

public interface Employee{
  public boolean isTimeToPay(Date payDate);
  public void pay();
  // NULL EMPLOYEE METHODS
  public static final Employee NULL = new Employee() {
     public boolean isTimeToPay(Date payDate) {
       return false;
     }                    // NOTE: class definition
     public void pay()
     {
     }                                  Anonymous inner class ensures
  };                                    single instance
}
NULL Object Code continued
public void testNull() throws Exception
  {
    Employee e = DB.getEmployee("Bob");
    if (e.isTimeToPay(new Date()))
      fail();
    assertEquals(Employee.NULL, e);
  }

								
To top