Vending Machine; working with encapsulation and cohesion

Emma Pr
5 min readMar 2, 2021

--

Today, after stressing myself out with thinking I would never be good enough at coding, I put on my big girl pants and got into Encapsulation. Now I hope you understand my tears after just reading that, because damn, was I lost. Encapsulation, however, is not that difficult! When you are encapsulating, you basically get your code into classes or private methods, where other pieces of code cannot just access it. Why would you do that? To prevent bugs when you write larger pieces of codes of course! You would not want to get loads of bugs when you are 1000 lines in, just because you used ‘x’ as a variable again. That being said, never use ‘x’ as a variable, as you want others to understand your code!

So, after cleaning up my tears and drinking a lovely cup of tea, I put together some code that uses Encapsulation. To make Encapsulation a bit easier for yourself, you can start putting together your ‘User stories’ and look at common themes in behaviour from the user stories. ‘User stories’ is the term I will be using to describe what you want from your code. Cohesion refers to the degree to which the elements that you will be using belong together.

The code that I wanted to write was that of a simple vending machine. The vending machine can do a few things that I will explain using user stories:

As a person,
So that I can buy candy,
I want to be able to see how much money I have in the machine.

As a person,
So that I can buy candy,
I want to put money into the machine.

As a person
So that I can buy candy,
I want to see how much candy is left in the machine.

As a person,
So that I can make sure the candy does not run out,
I want to be able to restock the machine.

As a person,
So that I can enjoy candy,
I want to vend candy from the machine.

That makes the whole idea of making a vending machine a LOT less scary, right? This is quite a simple one. I will keep adding new code I learn to this vending machine in future blogs. For now, this will do. Now we know that we have a few objects to look at and the messages that we want to send them:

We want the object ‘Funds’ to tell us about our balance and add money to our balance.
We want an object ‘Stock’ to tell us about our stock and allow us to restock.
We want an object ‘Vending Machine’ to vent candy.

Now, I already wrote the code that does all of this in this git repository: https://github.com/Emmapr123/Vending_Machine. But now I want to rewrite it to be more efficient, using Encapsulation. To do this, I will store every object, as stated above, in their own class, and even in their own file, with their own spec file.

To begin, I want to make my funds more efficient. To do that, I want my file ‘funds’, which stores my class ‘Funds’, to be able to tell me its status and to restock. The default status has to be 0.

require ‘funds’

describe Funds do
let(:candy) { Funds.new }

describe ‘status’ do
it ‘should return the status of the funds’ do
expect(candy.status).to eq “Your balance is 0 pounds”
end
end

describe ‘add_funds’ do
it ‘should add money to the funds’ do
expect(candy.add_funds(5)).to eq 5
end
end

end

Now that I have the specs for it, I can write the funds file.

class Funds
attr_accessor :balance

def initialize
@balance = 0
end

def status
“Your balance is #{balance} pounds”
end

def add_funds(money)
@balance += money
end

end

Still, not too hard, right? Next, I want to do the same for my stock!

require ‘stock’

describe Stock do
let(:candy) { Stock.new }

describe ‘status’ do
it ‘should show there is no more candy’ do
expect(candy.status).to eq “There is no candy left in the machine”
end

it ‘should show how many candy pieces are left’ do
candy.stock = 3
expect(candy.status).to eq “There are 3 pieces of candy left”
end
end

describe ‘restock’ do
it ‘should restock’ do
expect(candy.restock(5)).to eq 5
end
end

end

To make the machine friendly and grammatically correct, I wanted it to return different sentences when asked for their status. You do not have to do that per see.

class Stock
attr_accessor :stock

def initialize
@stock = 0
end

def status
if @stock == 0
“There is no candy left in the machine”
elsif @stock == 1
“There is 1 piece of candy left”
else
“There are #{@stock} pieces of candy left”
end
end

def restock(stock_amount)
@stock += stock_amount
end

end

All of that is still pretty readable, nothing too stressful, right? But how on earth will we put those separate files together and call for them in our vending machine?! That, my dear reader, looks a lot more stressful than it really is. To get our Vending machine to read those files and those classes, we just have to require them! Simple as that, we have done it before, in specs and gems, a walk in the park!

require_relative ‘stock’
require_relative ‘funds’

Now that we have our files put together, we can call these files inside of our code. And thus use them to write some specs. We want to know if we have enough funds and enough stock to vent candy, and if not, we want our user to know that.

require ‘vending_machine’

describe VendingMachine do
let(:candy) { VendingMachine.new ‘candy’, 10}

it ‘has a getter’ do
expect(candy.name).to eq ‘candy’
end

it ‘has a price getter/setter’ do
expect(candy.price).to eq 10
end

describe ‘vend’ do
it ‘does not vendy candy if not enough balance’ do
expect do
candy.balance = 1
candy.stock = 3
candy.vend
end.to output(“insufficient funds”).to_stdout
end
end

describe ‘vend’ do
it ‘vends candy as there is enough balance’ do
expect do
candy.stock = 3
candy.balance = 12
candy.vend
end.to output(“Enjoy your candy, your balance is now 2”).to_stdout
end
end

describe ‘vend’ do
it ‘cannot vend candy if the stock is too low’ do
expect do
candy.stock = 0
candy.vend
end.to output(“insufficient stock”).to_stdout
end
end

end

Now there is not much left for us to do. We just have to write the code for the vending machine, that uses both the ‘Funds’ class and the ‘Stock’ class!

class VendingMachine
attr_accessor :name, :price, :stock, :balance

def initialize(name, price)
@name = name
@price = price
@stock = Stock.new
@balance = Funds.new
end

def vend
if @stock == 0
print “insufficient stock”
elsif
@balance >= @price
@balance -= @price
@stock -= 1
print “Enjoy your #{name}, your balance is now #{balance}”
elsif @balance <= @price
print “insufficient funds”
end
end
end

Voila, those tears were clearly unnecessary. I hope this explains it alright. I would love to hear feedback on it or see how you did it if you try this yourself. Now it is time for a nice hot shower and some Mario cart for the rest of the night.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response