Skip to content

Instantly share code, notes, and snippets.

@bodhi
Created May 21, 2015 13:07
Show Gist options
  • Save bodhi/a52cc7361cef14a5d6d3 to your computer and use it in GitHub Desktop.
Save bodhi/a52cc7361cef14a5d6d3 to your computer and use it in GitHub Desktop.
RULES = {
"A" => [[1, 50],
[3, 130]],
"B" => [[1, 30],
[2, 45]],
"C" => [[1, 20]],
"D" => [[1, 15]]
}
class CheckOut < Struct.new(:rules)
def scan item
items[item] += 1
end
def total
items.map { |item, count|
price = 0
while count > 0
c, p = rules[item].select {|r, _| r <= count }.last
count -= c
price += p
end
price
}.inject(0, :+)
end
private
def items
@items ||= Hash.new(0)
end
end
class TestPrice < Test::Unit::TestCase
def price(goods)
co = CheckOut.new(RULES)
goods.split(//).each { |item| co.scan(item) }
co.total
end
def test_totals
assert_equal( 0, price(""))
assert_equal( 50, price("A"))
assert_equal( 80, price("AB"))
assert_equal(115, price("CDBA"))
assert_equal(100, price("AA"))
assert_equal(130, price("AAA"))
assert_equal(180, price("AAAA"))
assert_equal(230, price("AAAAA"))
assert_equal(260, price("AAAAAA"))
assert_equal(160, price("AAAB"))
assert_equal(175, price("AAABB"))
assert_equal(190, price("AAABBD"))
assert_equal(190, price("DABABA"))
end
def test_incremental
co = CheckOut.new(RULES)
assert_equal( 0, co.total)
co.scan("A"); assert_equal( 50, co.total)
co.scan("B"); assert_equal( 80, co.total)
co.scan("A"); assert_equal(130, co.total)
co.scan("A"); assert_equal(160, co.total)
co.scan("B"); assert_equal(175, co.total)
end
end
@bodhi
Copy link
Author

bodhi commented May 21, 2015

How can these be specified in such a way that the checkout doesn’t know about particular items and their pricing strategies? How can we make the design flexible enough so that we can add new styles of pricing rule in the future?

Currently the concept of converting an amount of items into a price is encoded into the pricing loop. This could be pushed out into a separate interface like PriceStrategy that would return the price of x items.

To cover the existing rules, you would only need a single parametric implementation with multiple instances for each SKU's rules.

To extend to other strategies like

buy two, get one free

or

$1.99/pound

you could provide separate implementations of PriceStrategy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment