main program
February 20, 2015 ยท View on GitHub
class PurchaseApprover
Implements the chain of responsibility pattern. Does not know anything
about the approval process, merely whether the current handler can approve
the request, or must pass it to a successor.
attr_reader :successor
def initialize successor @successor = successor end
def process_request request if approve_request request return elsif successor successor.process_request request else deny_request request end end
This may be overridden by a handler if it wants to provide a custom action
when it is the last member of the chain
def deny_request request puts "Your request for $#{request.amount} needs a board meeting!" end end
class AmountApprover < PurchaseApprover
Base class for approvers who only consider whether the request amount is
allowable
BASE = 500
def approve_request request if request.amount < self.class::ALLOWABLE print_approval request return true else return false end end end
class Manager < AmountApprover ALLOWABLE = 10 * BASE
def print_approval request puts "Manager will approve $#{request.amount}" end end
class Director < AmountApprover ALLOWABLE = 20 * BASE
def print_approval request puts "Director will approve $#{request.amount}" end end
class VicePresident < AmountApprover ALLOWABLE = 40 * BASE
def print_approval request puts "VicePresident will approve $#{request.amount}" end end
class President < AmountApprover ALLOWABLE = 60 * BASE
def print_approval request puts "President will approve $#{request.amount}" end end
class CFO < PurchaseApprover
An example of a handler that does not inherit from AmountApprover
Try adding it to the chain by implementing an annual budget that tracks the
total of all approved requests so far and whether we can afford one more.
def approve_request request if within_annual_budget? request puts "CFO will approve $#{request.amount}" return true else return false end end
def within_annual_budget? request # ... end end
class PurchaseRequest attr_reader :amount
def initialize(number, amount, purpose) @number = number @amount = amount @purpose = purpose end end
class CLP def initialize(*approvers) approvers = build_approvers(approvers) @authority = approvers.first end
def process_request request @authority.process_request request end
private
def build_approvers(approver_classes) [].tap do |approvers| approver_classes.reverse.inject(nil) do |successor, approver| approver.new(successor).tap {|approver| approvers.unshift approver } end end end end
main program
------------
approvers = CLP.new(Manager, Director, VicePresident, President)
loop do $stdout.flush puts puts "Enter the amount to check who should approve your expenditure." print ">> " amount = gets.to_i approvers.process_request PurchaseRequest.new(0, amount, 'General') end