Featured image of post CP1 - Vending Machine (Factory) - Design Pattern From Simple Things

CP1 - Vending Machine (Factory) - Design Pattern From Simple Things

Different beverages are scattered in different stores, it's too tiring to run through each store to find your beverage. You wish all beverages were sold in one place.

Vending Machine (Factory) is a creational design pattern: šŸ–¤šŸ–¤šŸ–¤šŸ–¤šŸ–¤

Although widely used, (Simple) Factory is not part of the GoF Design Pattern. It’s a term for a class creating objects without requiring any concrete classes.

Factory is too vague for me, so I use Vending Machine instead! Vending Machine is the same as Factory, but it’s more friendly :)

What is Vending Machine?

Beverage Vending Machine is a store holding a variety of beverages(Pepsi, Coke, Monster)

Just enter beverage ID(1, 2, 3) to Beverage Vending Machine, then Beverage Vending Machine will return your beverage.

Vending Machine Diagram

Why use Vending Machine?

It makes finding your beverage easier!

Question: I hate the Beverage Vending Machine, but I want to buy a Coke right now because I’m bloating.

Answer: You can find your Coke by searching in stores. If a store doesn’t sell it, try to find it again by going to another store, try again until you find it šŸ™‚

Where is the Coke Store

When to use Vending Machine?

Question: When do I go to the Beverage Vending Machine?

Answer: When you need a beverage Pepsi, Coke or Monster, right?

Input:

  • Having a menu of beverages:
    • Pepsi (ID = 1)
    • Coke (ID = 2)
    • Monster (ID = 3)
  • Beverages are being sold.
  • Knowing the beverage you need to buy Coke.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import abc


# Input 1: Having a menu of beverages:
class MENU:
    PEPSI = 1
    COKE = 2
    MONSTER = 3


class Beverage(metaclass=abc.ABCMeta):
    id = ""
    carbon_dioxide = 0

    # @abc.abstractmethod means: in the concrete class, The method have to re-defined
    @abc.abstractmethod
    def make_burp(self):
        return ""


# Input 2: Beverages are being sold.
class Pepsi(Beverage):
    id = MENU.PEPSI
    carbon_dioxide = 3

    def make_burp(self):
        return f"B{'U' * self.carbon_dioxide}RP"


# Input 2: Beverages are being sold.
class Coke(Beverage):
    id = MENU.COKE
    carbon_dioxide = 2

    def make_burp(self):
        return f"BU{'R' * self.carbon_dioxide}P"


# Input 2: Beverages are being sold.
class Monster(Beverage):
    id = MENU.MONSTER
    carbon_dioxide = 1

    def make_burp(self):
        return f"BURP"

Expected Output:

  • Get a beverage Coke
  • Drink your beverage and make a burp BURRP
  • Get all carbonated_beverages
1
2
3
4
5
6
generate a beverage by id
<Coke object>
BURRP

generate all carbonated beverages
[<Pepsi object>, <Coke object>]

girl burp

How to implement Vending Machine?

Non-Vending Machine implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
if __name__ == "__main__":
    print("generate a beverage by id")
    beverage = None
    for beverage_cls in [Pepsi, Coke, Monster]:
        # Input 3: Knowing the beverage you need to buy.
        if MENU.COKE == beverage_cls.id:
            beverage = beverage_cls()
    # Expected Output 1: Get a beverage
    print(beverage)
    # Expected Output 2: Drink your beverage and make a burp
    print(beverage.make_burp())

    print("generate all carbonated beverages")
    carbonated_beverages = []
    for beverage_cls in [Pepsi, Coke, Monster]:
        if beverage_cls.carbon_dioxide > 1:
            carbonated_beverages.append(beverage_cls())
    print(carbonated_beverages)

Vending Machine implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class BeverageVendingMachine:

    @property
    def subclasses(self):
        # [<class 'Pepsi'>, <class 'Coke'>, <class 'Monster'>]
        return Beverage.__subclasses__()

    @property
    def subclass_mapping(self):
        # {1: <class 'Pepsi'>, 2: <class 'Coke'>, 3: <class 'Monster'>}
        return {beverage.id: beverage for beverage in self.subclasses}

    def generate(self, key):
        subclass = self.subclass_mapping[key]
        instance = subclass()
        return instance

    @property
    def generate_carbonated_beverages(self):
        return [subclass() for subclass in self.subclasses if subclass.carbon_dioxide > 1]


if __name__ == "__main__":
    beverage_vending_machine = BeverageVendingMachine()

    print("generate a beverage by id")
    # Input 3: Knowing the beverage you need to buy.
    coke = beverage_vending_machine.generate(MENU.COKE)
    # Expected Output 1: Get a beverage
    print(coke)
    # Expected Output 2: Drink your beverage and make a burp
    print(coke.make_burp())
    
    print("generate all carbonated beverages")
    carbonated_beverages = beverage_vending_machine.generate_carbonated_beverages
    print(carbonated_beverages)

Source Code

Made with the laziness šŸ¦„
by a busy guy