Part 13: Constrained genericity

 
 
 

13.1 Specification

        The specification is unchanged from the previous case study.
 
 

13.2 Analysis

        There is no analysis because the specification is unchanged.
 
 

13.3 Design: a keyed list

        Constrained genericity is used to move the list scan code from ATM and TELLER to KEY_LIST [T]. Class KEY_LIST can be used to store and retrieve any object with an integer key. The minimum that we need is to define a keyed list of customers, but a more general solution is shown that works for any object with an INTEGER key. The construction of a class that is a keyed list requires a deferred class that has a key and a match routine (class KEY) a child that inherits this parent and effects the match routine (class CUSTOMER) and a constrained generic class (class KEY_LIST) The constrained class has KEY as its constraint in the class header, and contains code to look up an element of the list using a key.
 
 

13.4 Charts
 


 
 
 
 

13.5 Design: a keyed, storable list

        A keyed, storable list class is created by combining the inheritance hierarchies from the two applications, and moving the lookup code from the clients (TELLER and ATM) into the keyed class. The inheritance hierarchy for the keyed, storable list class is shown below.
 


 
 
 
 

13.6 Solution code

        A full listing for class KEYED is shown below, then its inheritance in CUSTOMER The following pages shows the client code to use a keyed list in TELLER and ATM, followed by a full listing for KEY_LIST .
 

class KEYED

feature {NONE}
        id: INTEGER

feature {ANY}
        set_id (key: INTEGER) is
                        -- store the key in id
               do
                       id := key
               end -- set_id

        match (key: INTEGER): BOOLEAN is
                        -- does the key match the id?
               do
                       Result := key = id
               end -- match

        show_id is
                        -- show the customer id
               do
                       io.putstring ("%NThe customer id is ")
                       io.putint (id)
               end -- show_id

end -- class KEYED
 

class CUSTOMER

inherit
        KEYED
        PERSON
        ...
end -- class CUSTOMER
 

class TELLER

creation {BANK}
        make

feature {NONE}
        patrons: KEY_LIST[CUSTOMER]

        make (customers: KEY_LIST [CUSTOMER]) is
                        -- store the customers in patrons
               do patrons := customers end -- make
        ...
        new_accounts is
                        -- add any new accounts for existing customers
               do
                       from ask_for_more_accounts
                       until no_more
                       loop
                               read_id
                               patrons.find (io.lastint)
                               if patrons.found
                               then patrons.item.accounts.make
                               else io.putstring ("%NThat is not a valid userId")
                               end
                               ask_for_more_accounts
                       end
               end -- new_accounts
        ...
end -- class TELLER
 

class ATM

creation {BANK}
        make

feature {NONE}
        patrons: KEY_LIST [CUSTOMER]
        make (customers: KEY_LIST [CUSTOMER]) is
                        -- store the customers in patrons
               do patrons := customers end -- make
        ...
        serve_customer (id: INTEGER) is
                        -- find the customer with the input id
                        -- if the customer exists, transfer control
               do
                       patrons.find (id)
                       if patrons.found
                       then patrons.item.login
                       else io.putstring ("%NThat is not a valid userId")
                       end
               end -- serve_customer
        ...
end -- class ATM
 

class KEY_LIST [T -> KEYED]

inherit
        STORABLE
        LINKED_LIST [T]

creation {BANK}
        make

feature {TELLER, ATM}
        get_id is
                        -- get a customer's user identifier
               do
                       io.putstring ("%N%TEnter user id: ")
                       io.readint
               end -- get_id

        find (key: INTEGER) is
                        -- set the cursor at the person with this key
                        -- if no such person, cursor is offright
               do
                       from start
                       until after or else item.match (key)
                       loop forth
                       end
               end -- find

        found: BOOLEAN is
                        -- is the cursor in the list?
               do
                       Result := not after
               end -- found

end -- class KEY_LIST